From f7acea2683c6124854bfe20e7127e4dfba344d3e Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 24 Apr 2020 00:14:03 +0200 Subject: [PATCH 01/36] Register redundant_field_names and non_expressive_names as early passes --- clippy_lints/src/lib.rs | 12 ++++++------ src/driver.rs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index b8415fa3af1..9057de99029 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -341,13 +341,8 @@ mod reexport { /// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass. /// /// Used in `./src/driver.rs`. -pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, conf: &Conf) { +pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore) { store.register_pre_expansion_pass(|| box write::Write::default()); - store.register_pre_expansion_pass(|| box redundant_field_names::RedundantFieldNames); - let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; - store.register_pre_expansion_pass(move || box non_expressive_names::NonExpressiveNames { - single_char_binding_names_threshold, - }); store.register_pre_expansion_pass(|| box attrs::DeprecatedCfgAttribute); store.register_pre_expansion_pass(|| box dbg_macro::DbgMacro); } @@ -1051,6 +1046,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box unnamed_address::UnnamedAddress); store.register_late_pass(|| box dereference::Dereferencing); store.register_late_pass(|| box future_not_send::FutureNotSend); + store.register_early_pass(|| box redundant_field_names::RedundantFieldNames); + let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; + store.register_early_pass(move || box non_expressive_names::NonExpressiveNames { + single_char_binding_names_threshold, + }); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), diff --git a/src/driver.rs b/src/driver.rs index 2c699998ea9..928497ba5e4 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -79,7 +79,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks { 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, &conf); + clippy_lints::register_pre_expansion_lints(&mut lint_store); clippy_lints::register_renamed(&mut lint_store); })); From 485229c4a3d6a2fbe40f5a6976a33144a27497c6 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Tue, 12 May 2020 16:26:55 +0200 Subject: [PATCH 02/36] Fix fallout in redundant_field_names --- clippy_lints/src/redundant_field_names.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index b12c3c344ef..2a81170e49e 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -2,6 +2,7 @@ use crate::utils::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}; declare_clippy_lint! { @@ -36,6 +37,9 @@ declare_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]); impl EarlyLintPass for RedundantFieldNames { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if in_external_macro(cx.sess, expr.span) { + return; + } if let ExprKind::Struct(_, ref fields, _) = expr.kind { for field in fields { if field.is_shorthand { From efd3dcff97f67f376e354c047133ce9044c52991 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Tue, 12 May 2020 16:50:00 +0200 Subject: [PATCH 03/36] Fix fallout in similar_names --- clippy_lints/src/non_expressive_names.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 45809b35986..ef3b1da1b0b 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -5,6 +5,7 @@ use rustc_ast::ast::{ use rustc_ast::attr; use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor}; 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::symbol::SymbolStr; @@ -354,12 +355,20 @@ impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> { impl EarlyLintPass for NonExpressiveNames { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + if in_external_macro(cx.sess, item.span) { + return; + } + if let ItemKind::Fn(_, ref sig, _, Some(ref blk)) = item.kind { do_check(self, cx, &item.attrs, &sig.decl, blk); } } fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &AssocItem) { + if in_external_macro(cx.sess, item.span) { + return; + } + if let AssocItemKind::Fn(_, ref sig, _, Some(ref blk)) = item.kind { do_check(self, cx, &item.attrs, &sig.decl, blk); } From bb37a0f948b02e6434dbe3ea615960052d37f784 Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Wed, 27 May 2020 00:06:50 +0200 Subject: [PATCH 04/36] Avoid triggering similar names on code from expansion --- clippy_lints/src/new_without_default.rs | 10 +++++----- clippy_lints/src/non_expressive_names.rs | 6 +++++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 19e06ab66c4..1ad631abe91 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -126,8 +126,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault { return; } if sig.decl.inputs.is_empty() && name == sym!(new) && cx.access_levels.is_reachable(id) { - let self_did = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent_item(id)); - let self_ty = cx.tcx.type_of(self_did); + 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 let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT); @@ -148,10 +148,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault { // generics if_chain! { if let Some(ref impling_types) = self.impling_types; - if let Some(self_def) = cx.tcx.type_of(self_did).ty_adt_def(); - if let Some(self_def_id) = self_def.did.as_local(); + 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_def_id); + let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did); if impling_types.contains(&self_id) { return; } diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index ef3b1da1b0b..5331bf26e05 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -132,7 +132,11 @@ struct SimilarNamesNameVisitor<'a, 'tcx, 'b>(&'b mut SimilarNamesLocalVisitor<'a impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> { fn visit_pat(&mut self, pat: &'tcx Pat) { match pat.kind { - PatKind::Ident(_, ident, _) => self.check_ident(ident), + PatKind::Ident(_, ident, _) => { + if !pat.span.from_expansion() { + self.check_ident(ident); + } + }, PatKind::Struct(_, ref fields, _) => { for field in fields { if !field.is_shorthand { From 201999ccfd18a9debe1f186f30f40659ebc6b933 Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Mon, 13 Jul 2020 10:33:25 -0700 Subject: [PATCH 05/36] 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(-) 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 From d067d0352bfc5a6979f477bc96c969b040437618 Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Tue, 14 Jul 2020 08:18:15 +0200 Subject: [PATCH 06/36] Add test for `needless_range_loop` issue Closes #2277 This was fixed when we fixed #2542. --- tests/ui/needless_range_loop2.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/ui/needless_range_loop2.rs b/tests/ui/needless_range_loop2.rs index 2ed1b09bece..a82b1159161 100644 --- a/tests/ui/needless_range_loop2.rs +++ b/tests/ui/needless_range_loop2.rs @@ -83,3 +83,13 @@ fn main() { println!("{}", arr[i]); } } + +mod issue2277 { + pub fn example(list: &[[f64; 3]]) { + let mut x: [f64; 3] = [10.; 3]; + + for i in 0..3 { + x[i] = list.iter().map(|item| item[i]).sum::(); + } + } +} From 6f25adbd5a1600653e8edf8de7135c397d73c07a Mon Sep 17 00:00:00 2001 From: flip1995 Date: Tue, 14 Jul 2020 14:59:59 +0200 Subject: [PATCH 07/36] Merge commit '2ca58e7dda4a9eb142599638c59dc04d15961175' into clippyup --- .github/ISSUE_TEMPLATE/new_lint.md | 2 +- .github/workflows/clippy_bors.yml | 3 +- CHANGELOG.md | 6 + CONTRIBUTING.md | 2 +- clippy_lints/src/attrs.rs | 115 +++-- clippy_lints/src/await_holding_lock.rs | 2 +- clippy_lints/src/collapsible_if.rs | 4 +- clippy_lints/src/comparison_chain.rs | 5 +- clippy_lints/src/deprecated_lints.rs | 10 +- clippy_lints/src/dereference.rs | 10 +- clippy_lints/src/eq_op.rs | 30 +- clippy_lints/src/escape.rs | 5 +- clippy_lints/src/eta_reduction.rs | 5 +- clippy_lints/src/floating_point_arithmetic.rs | 227 +++++++++- clippy_lints/src/formatting.rs | 12 +- clippy_lints/src/functions.rs | 8 +- clippy_lints/src/if_let_mutex.rs | 9 +- clippy_lints/src/len_zero.rs | 16 +- clippy_lints/src/let_and_return.rs | 21 +- clippy_lints/src/lib.rs | 49 ++- clippy_lints/src/lifetimes.rs | 16 +- clippy_lints/src/literal_representation.rs | 9 +- clippy_lints/src/loops.rs | 42 +- clippy_lints/src/map_identity.rs | 126 ++++++ clippy_lints/src/matches.rs | 412 +++++++++++++++++- clippy_lints/src/methods/mod.rs | 28 +- .../src/methods/unnecessary_filter_map.rs | 11 +- clippy_lints/src/minmax.rs | 25 +- clippy_lints/src/misc.rs | 113 ++--- 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/option_if_let_else.rs | 267 ++++++++++++ clippy_lints/src/pattern_type_mismatch.rs | 311 +++++++++++++ clippy_lints/src/precedence.rs | 10 +- clippy_lints/src/ranges.rs | 12 +- .../src/redundant_pattern_matching.rs | 260 ----------- clippy_lints/src/regex.rs | 64 +-- clippy_lints/src/repeat_once.rs | 82 ++++ clippy_lints/src/returns.rs | 18 +- clippy_lints/src/shadow.rs | 9 +- clippy_lints/src/temporary_assignment.rs | 8 +- clippy_lints/src/trait_bounds.rs | 27 +- clippy_lints/src/types.rs | 52 +-- clippy_lints/src/unnamed_address.rs | 14 +- clippy_lints/src/unnecessary_sort_by.rs | 48 +- clippy_lints/src/unnested_or_patterns.rs | 8 +- clippy_lints/src/use_self.rs | 13 +- clippy_lints/src/utils/ast_utils.rs | 5 +- clippy_lints/src/utils/attrs.rs | 71 +-- clippy_lints/src/utils/conf.rs | 2 + clippy_lints/src/utils/hir_utils.rs | 19 +- clippy_lints/src/utils/mod.rs | 88 ++-- clippy_lints/src/utils/numeric_literal.rs | 8 +- clippy_lints/src/utils/paths.rs | 1 - clippy_lints/src/utils/sugg.rs | 44 +- clippy_lints/src/write.rs | 30 +- src/driver.rs | 9 +- src/lintlist/mod.rs | 47 +- tests/compile-test.rs | 12 +- .../multiple_crate_versions/fail/Cargo.lock | 109 +++++ .../fail/src/main.stderr | 2 +- .../toml_unknown_key/conf_unknown_key.stderr | 2 +- tests/ui/attrs.rs | 6 + tests/ui/attrs.stderr | 33 +- tests/ui/clone_on_copy.fixed | 40 ++ tests/ui/clone_on_copy.rs | 40 ++ tests/ui/clone_on_copy.stderr | 34 ++ .../ui/cmp_owned/asymmetric_partial_eq.fixed | 93 ++++ tests/ui/cmp_owned/asymmetric_partial_eq.rs | 93 ++++ .../ui/cmp_owned/asymmetric_partial_eq.stderr | 46 ++ tests/ui/collapsible_else_if.stderr | 14 +- tests/ui/collapsible_if.stderr | 14 +- tests/ui/deprecated.rs | 1 + tests/ui/deprecated.stderr | 8 +- tests/ui/find_map.rs | 1 + tests/ui/find_map.stderr | 2 +- tests/ui/floating_point_hypot.fixed | 14 + tests/ui/floating_point_hypot.rs | 14 + tests/ui/floating_point_hypot.stderr | 22 + tests/ui/floating_point_log.fixed | 10 +- tests/ui/floating_point_log.rs | 10 +- tests/ui/floating_point_log.stderr | 20 +- tests/ui/floating_point_logbase.fixed | 16 + tests/ui/floating_point_logbase.rs | 16 + tests/ui/floating_point_logbase.stderr | 28 ++ tests/ui/floating_point_mul_add.fixed | 5 + tests/ui/floating_point_mul_add.rs | 5 + tests/ui/floating_point_mul_add.stderr | 8 +- tests/ui/floating_point_powf.fixed | 4 +- tests/ui/floating_point_powf.rs | 4 +- tests/ui/floating_point_powf.stderr | 8 +- tests/ui/floating_point_powi.fixed | 19 + tests/ui/floating_point_powi.rs | 19 + tests/ui/floating_point_powi.stderr | 40 ++ tests/ui/floating_point_rad.fixed | 13 + tests/ui/floating_point_rad.rs | 13 + tests/ui/floating_point_rad.stderr | 16 + tests/ui/map_flatten.fixed | 1 + tests/ui/map_flatten.rs | 1 + tests/ui/map_flatten.stderr | 4 +- tests/ui/map_identity.fixed | 23 + tests/ui/map_identity.rs | 25 ++ tests/ui/map_identity.stderr | 37 ++ tests/ui/match_expr_like_matches_macro.fixed | 36 ++ tests/ui/match_expr_like_matches_macro.rs | 48 ++ tests/ui/match_expr_like_matches_macro.stderr | 52 +++ tests/ui/neg_cmp_op_on_partial_ord.rs | 2 +- tests/ui/option_if_let_else.fixed | 74 ++++ tests/ui/option_if_let_else.rs | 92 ++++ tests/ui/option_if_let_else.stderr | 151 +++++++ tests/ui/pattern_type_mismatch/mutability.rs | 40 ++ .../pattern_type_mismatch/mutability.stderr | 19 + .../pattern_alternatives.rs | 24 + .../pattern_alternatives.stderr | 27 ++ .../pattern_type_mismatch/pattern_structs.rs | 45 ++ .../pattern_structs.stderr | 67 +++ .../pattern_type_mismatch/pattern_tuples.rs | 57 +++ .../pattern_tuples.stderr | 83 ++++ tests/ui/pattern_type_mismatch/syntax.rs | 146 +++++++ tests/ui/pattern_type_mismatch/syntax.stderr | 79 ++++ tests/ui/range_plus_minus_one.fixed | 1 + tests/ui/range_plus_minus_one.rs | 1 + tests/ui/range_plus_minus_one.stderr | 18 +- tests/ui/redundant_pattern_matching.fixed | 8 +- tests/ui/redundant_pattern_matching.rs | 8 +- tests/ui/redundant_pattern_matching.stderr | 56 +-- ...undant_pattern_matching_const_result.fixed | 2 +- ...redundant_pattern_matching_const_result.rs | 2 +- tests/ui/regex.rs | 2 +- tests/ui/repeat_once.fixed | 16 + tests/ui/repeat_once.rs | 16 + tests/ui/repeat_once.stderr | 40 ++ tests/ui/single_match_else.rs | 51 +++ tests/ui/single_match_else.stderr | 44 +- tests/ui/type_repetition_in_bounds.rs | 55 ++- tests/ui/type_repetition_in_bounds.stderr | 18 +- tests/ui/unnecessary_clone.rs | 25 -- tests/ui/unnecessary_clone.stderr | 58 +-- tests/ui/unnecessary_sort_by.fixed | 46 +- tests/ui/unnecessary_sort_by.rs | 46 +- tests/ui/unnested_or_patterns3.rs | 6 + 143 files changed, 4317 insertions(+), 1084 deletions(-) create mode 100644 clippy_lints/src/map_identity.rs create mode 100644 clippy_lints/src/option_if_let_else.rs create mode 100644 clippy_lints/src/pattern_type_mismatch.rs delete mode 100644 clippy_lints/src/redundant_pattern_matching.rs create mode 100644 clippy_lints/src/repeat_once.rs create mode 100644 tests/ui-cargo/multiple_crate_versions/fail/Cargo.lock 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 create mode 100644 tests/ui/cmp_owned/asymmetric_partial_eq.fixed create mode 100644 tests/ui/cmp_owned/asymmetric_partial_eq.rs create mode 100644 tests/ui/cmp_owned/asymmetric_partial_eq.stderr create mode 100644 tests/ui/floating_point_hypot.fixed create mode 100644 tests/ui/floating_point_hypot.rs create mode 100644 tests/ui/floating_point_hypot.stderr create mode 100644 tests/ui/floating_point_logbase.fixed create mode 100644 tests/ui/floating_point_logbase.rs create mode 100644 tests/ui/floating_point_logbase.stderr create mode 100644 tests/ui/floating_point_powi.fixed create mode 100644 tests/ui/floating_point_powi.rs create mode 100644 tests/ui/floating_point_powi.stderr create mode 100644 tests/ui/floating_point_rad.fixed create mode 100644 tests/ui/floating_point_rad.rs create mode 100644 tests/ui/floating_point_rad.stderr create mode 100644 tests/ui/map_identity.fixed create mode 100644 tests/ui/map_identity.rs create mode 100644 tests/ui/map_identity.stderr create mode 100644 tests/ui/match_expr_like_matches_macro.fixed create mode 100644 tests/ui/match_expr_like_matches_macro.rs create mode 100644 tests/ui/match_expr_like_matches_macro.stderr create mode 100644 tests/ui/option_if_let_else.fixed create mode 100644 tests/ui/option_if_let_else.rs create mode 100644 tests/ui/option_if_let_else.stderr create mode 100644 tests/ui/pattern_type_mismatch/mutability.rs create mode 100644 tests/ui/pattern_type_mismatch/mutability.stderr create mode 100644 tests/ui/pattern_type_mismatch/pattern_alternatives.rs create mode 100644 tests/ui/pattern_type_mismatch/pattern_alternatives.stderr create mode 100644 tests/ui/pattern_type_mismatch/pattern_structs.rs create mode 100644 tests/ui/pattern_type_mismatch/pattern_structs.stderr create mode 100644 tests/ui/pattern_type_mismatch/pattern_tuples.rs create mode 100644 tests/ui/pattern_type_mismatch/pattern_tuples.stderr create mode 100644 tests/ui/pattern_type_mismatch/syntax.rs create mode 100644 tests/ui/pattern_type_mismatch/syntax.stderr create mode 100644 tests/ui/repeat_once.fixed create mode 100644 tests/ui/repeat_once.rs create mode 100644 tests/ui/repeat_once.stderr create mode 100644 tests/ui/unnested_or_patterns3.rs diff --git a/.github/ISSUE_TEMPLATE/new_lint.md b/.github/ISSUE_TEMPLATE/new_lint.md index 70445d7ef25..98fd0df685f 100644 --- a/.github/ISSUE_TEMPLATE/new_lint.md +++ b/.github/ISSUE_TEMPLATE/new_lint.md @@ -12,7 +12,7 @@ labels: L-lint - Kind: *See for list of lint kinds* -*What benefit of this lint over old code?* +*What is the advantage of the recommended code over the original code* For example: - Remove bounce checking inserted by ... diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 0c80394f03e..fd0cd7a1890 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -240,7 +240,8 @@ jobs: - 'Geal/nom' - 'rust-lang/stdarch' - 'serde-rs/serde' - - 'chronotope/chrono' + # FIXME: chrono currently cannot be compiled with `--all-targets` + # - 'chronotope/chrono' - 'hyperium/hyper' - 'rust-random/rand' - 'rust-lang/futures-rs' diff --git a/CHANGELOG.md b/CHANGELOG.md index adc945a6944..5d08b44ba40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1352,6 +1352,7 @@ Released 2018-09-13 [`bad_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#bad_bit_mask [`bind_instead_of_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map [`blacklisted_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#blacklisted_name +[`blanket_clippy_restriction_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#blanket_clippy_restriction_lints [`blocks_in_if_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_if_conditions [`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison [`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const @@ -1508,9 +1509,11 @@ Released 2018-09-13 [`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone [`map_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry [`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten +[`map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_identity [`map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or [`match_as_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_as_ref [`match_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_bool +[`match_like_matches_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro [`match_on_vec_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_on_vec_items [`match_overlapping_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_overlapping_arm [`match_ref_pats`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_ref_pats @@ -1575,6 +1578,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_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 [`option_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_option @@ -1586,6 +1590,7 @@ Released 2018-09-13 [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite +[`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence [`print_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_literal @@ -1612,6 +1617,7 @@ Released 2018-09-13 [`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro +[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts [`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs [`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9f7bdcb1be7..69a734e4ee4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -245,7 +245,7 @@ this to work, you will need the fix of `git subtree` available [here][gitgitgadget-pr]. [gitgitgadget-pr]: https://github.com/gitgitgadget/git/pull/493 -[subtree]: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#external-dependencies-subtree +[subtree]: https://rustc-dev-guide.rust-lang.org/contributing.html#external-dependencies-subtree [`rust-lang/rust`]: https://github.com/rust-lang/rust ## Issue and PR triage diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 3f7d6ba6467..ef01364b7d9 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -2,8 +2,8 @@ use crate::reexport::Name; use crate::utils::{ - first_line_of_span, is_present_in_source, match_def_path, paths, snippet_opt, span_lint, span_lint_and_sugg, - span_lint_and_then, without_block_comments, + first_line_of_span, is_present_in_source, match_def_path, paths, snippet_opt, span_lint, span_lint_and_help, + span_lint_and_sugg, span_lint_and_then, without_block_comments, }; use if_chain::if_chain; use rustc_ast::ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; @@ -17,7 +17,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::symbol::Symbol; +use rustc_span::symbol::{Symbol, SymbolStr}; use semver::Version; static UNIX_SYSTEMS: &[&str] = &[ @@ -182,6 +182,29 @@ declare_clippy_lint! { "unknown_lints for scoped Clippy lints" } +declare_clippy_lint! { + /// **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. + /// These lints should only be enabled on a lint-by-lint basis and with careful consideration. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// Bad: + /// ```rust + /// #![deny(clippy::restriction)] + /// ``` + /// + /// Good: + /// ```rust + /// #![deny(clippy::as_conversions)] + /// ``` + pub BLANKET_CLIPPY_RESTRICTION_LINTS, + style, + "enabling the complete restriction group" +} + declare_clippy_lint! { /// **What it does:** Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it /// with `#[rustfmt::skip]`. @@ -249,15 +272,17 @@ declare_lint_pass!(Attributes => [ DEPRECATED_SEMVER, USELESS_ATTRIBUTE, UNKNOWN_CLIPPY_LINTS, + BLANKET_CLIPPY_RESTRICTION_LINTS, ]); 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() { - match &*ident.as_str() { + let ident = &*ident.as_str(); + match ident { "allow" | "warn" | "deny" | "forbid" => { - check_clippy_lint_names(cx, items); + check_clippy_lint_names(cx, ident, items); }, _ => {}, } @@ -363,38 +388,43 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { } } -#[allow(clippy::single_match_else)] -fn check_clippy_lint_names(cx: &LateContext<'_>, items: &[NestedMetaItem]) { - let lint_store = cx.lints(); - for lint in items { +fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMetaItem]) { + fn extract_name(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.as_str() == "clippy"; - let name = meta_item.path.segments.last().unwrap().ident.name; - if let CheckLintNameResult::Tool(Err((None, _))) = lint_store.check_lint_name( - &name.as_str(), - Some(tool_name.name), - ); + let lint_name = meta_item.path.segments.last().unwrap().ident.name; then { + return Some(lint_name.as_str()); + } + } + None + } + + let lint_store = cx.lints(); + for lint in items { + if let Some(lint_name) = extract_name(lint) { + if let CheckLintNameResult::Tool(Err((None, _))) = + lint_store.check_lint_name(&lint_name, Some(sym!(clippy))) + { span_lint_and_then( cx, UNKNOWN_CLIPPY_LINTS, lint.span(), - &format!("unknown clippy lint: clippy::{}", name), + &format!("unknown clippy lint: clippy::{}", lint_name), |diag| { - let name_lower = name.as_str().to_lowercase(); - let symbols = lint_store.get_lints().iter().map( - |l| Symbol::intern(&l.name_lower()) - ).collect::>(); - let sugg = find_best_match_for_name( - symbols.iter(), - &format!("clippy::{}", name_lower), - None, - ); - if name.as_str().chars().any(char::is_uppercase) - && lint_store.find_lints(&format!("clippy::{}", name_lower)).is_ok() { + let name_lower = lint_name.to_lowercase(); + let symbols = lint_store + .get_lints() + .iter() + .map(|l| Symbol::intern(&l.name_lower())) + .collect::>(); + let sugg = find_best_match_for_name(symbols.iter(), &format!("clippy::{}", name_lower), None); + if lint_name.chars().any(char::is_uppercase) + && lint_store.find_lints(&format!("clippy::{}", name_lower)).is_ok() + { diag.span_suggestion( lint.span(), "lowercase the lint name", @@ -409,10 +439,19 @@ fn check_clippy_lint_names(cx: &LateContext<'_>, items: &[NestedMetaItem]) { Applicability::MachineApplicable, ); } - } + }, + ); + } else if lint_name == "restriction" && ident != "allow" { + span_lint_and_help( + cx, + BLANKET_CLIPPY_RESTRICTION_LINTS, + lint.span(), + "restriction lints are not meant to be all enabled", + None, + "try enabling only the lints you really need", ); } - }; + } } } @@ -442,15 +481,14 @@ 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 { @@ -460,11 +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 { - 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/await_holding_lock.rs b/clippy_lints/src/await_holding_lock.rs index 20b91bc0f1b..d337262dfa6 100644 --- a/clippy_lints/src/await_holding_lock.rs +++ b/clippy_lints/src/await_holding_lock.rs @@ -11,7 +11,7 @@ declare_clippy_lint! { /// non-async-aware MutexGuard. /// /// **Why is this bad?** The Mutex types found in syd::sync and parking_lot - /// are not designed to operator in an async context across await points. + /// 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 /// type. Many asynchronous foundation crates provide such a Mutex type. The diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 8090f4673aa..42bff564de0 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -115,7 +115,7 @@ fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, else_: &ast::Expr) { COLLAPSIBLE_IF, block.span, "this `else { if .. }` block can be collapsed", - "try", + "collapse nested if block", snippet_block_with_applicability(cx, else_.span, "..", Some(block.span), &mut applicability).into_owned(), applicability, ); @@ -142,7 +142,7 @@ fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: & let rhs = Sugg::ast(cx, check_inner, ".."); diag.span_suggestion( expr.span, - "try", + "collapse nested if block", format!( "if {} {}", lhs.and(&rhs), 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/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index 6e8ca647dd7..818d8188a78 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -153,5 +153,13 @@ declare_deprecated_lint! { /// /// **Deprecation reason:** Associated-constants are now preferred. pub REPLACE_CONSTS, - "associated-constants `MIN`/`MAX` of integers are prefer to `{min,max}_value()` and module constants" + "associated-constants `MIN`/`MAX` of integers are prefered to `{min,max}_value()` and module constants" +} + +declare_deprecated_lint! { + /// **What it does:** Nothing. This lint has been deprecated. + /// + /// **Deprecation reason:** The regex! macro does not exist anymore. + pub REGEX_MACRO, + "the regex! macro has been removed from the regex crate in 2018" } diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index d740d88a77d..323cad7fa1a 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -73,9 +73,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { fn lint_deref(cx: &LateContext<'_>, method_name: &str, call_expr: &Expr<'_>, var_span: Span, expr_span: Span) { match method_name { "deref" => { - if cx.tcx.lang_items().deref_trait().map_or(false, |id| { + let impls_deref_trait = cx.tcx.lang_items().deref_trait().map_or(false, |id| { implements_trait(cx, cx.tables().expr_ty(&call_expr), id, &[]) - }) { + }); + if impls_deref_trait { span_lint_and_sugg( cx, EXPLICIT_DEREF_METHODS, @@ -88,9 +89,10 @@ fn lint_deref(cx: &LateContext<'_>, method_name: &str, call_expr: &Expr<'_>, var } }, "deref_mut" => { - if cx.tcx.lang_items().deref_mut_trait().map_or(false, |id| { + let impls_deref_mut_trait = cx.tcx.lang_items().deref_mut_trait().map_or(false, |id| { implements_trait(cx, cx.tables().expr_ty(&call_expr), id, &[]) - }) { + }); + if impls_deref_mut_trait { span_lint_and_sugg( cx, EXPLICIT_DEREF_METHODS, diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index cbc93d772dd..01eff28cb19 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 b10181062ff..ceb3c40d869 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/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 4efd0689267..3087d6a940a 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -1,11 +1,11 @@ use crate::consts::{ constant, constant_simple, Constant, - Constant::{F32, F64}, + Constant::{Int, F32, F64}, }; -use crate::utils::{higher, numeric_literal, span_lint_and_sugg, sugg, SpanlessEq}; +use crate::utils::{get_parent_expr, higher, numeric_literal, span_lint_and_sugg, sugg, SpanlessEq}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; +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}; @@ -293,6 +293,121 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { } } +fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { + if let Some((value, _)) = constant(cx, cx.tables(), &args[1]) { + if value == Int(2) { + if let Some(parent) = get_parent_expr(cx, expr) { + if let Some(grandparent) = get_parent_expr(cx, parent) { + if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, _, args, _) = grandparent.kind { + if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() { + return; + } + } + } + + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Add, .. + }, + ref lhs, + ref rhs, + ) = parent.kind + { + let other_addend = if lhs.hir_id == expr.hir_id { rhs } else { lhs }; + + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + parent.span, + "square can be computed more efficiently", + "consider using", + format!( + "{}.mul_add({}, {})", + Sugg::hir(cx, &args[0], ".."), + Sugg::hir(cx, &args[0], ".."), + Sugg::hir(cx, &other_addend, ".."), + ), + Applicability::MachineApplicable, + ); + + return; + } + } + + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "square can be computed more efficiently", + "consider using", + format!("{} * {}", Sugg::hir(cx, &args[0], ".."), Sugg::hir(cx, &args[0], "..")), + Applicability::MachineApplicable, + ); + } + } +} + +fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option { + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Add, .. + }, + ref add_lhs, + ref 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 are_exprs_equal(cx, lmul_lhs, lmul_rhs); + if are_exprs_equal(cx, rmul_lhs, rmul_rhs); + then { + return Some(format!("{}.hypot({})", Sugg::hir(cx, &lmul_lhs, ".."), Sugg::hir(cx, &rmul_lhs, ".."))); + } + } + + // check if expression of the form x.powi(2) + y.powi(2) + if_chain! { + if let ExprKind::MethodCall( + PathSegment { ident: lmethod_name, .. }, + ref _lspan, + ref largs, + _ + ) = add_lhs.kind; + if let ExprKind::MethodCall( + PathSegment { ident: rmethod_name, .. }, + ref _rspan, + ref rargs, + _ + ) = add_rhs.kind; + if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi"; + if let Some((lvalue, _)) = constant(cx, cx.tables(), &largs[1]); + if let Some((rvalue, _)) = constant(cx, cx.tables(), &rargs[1]); + if Int(2) == lvalue && Int(2) == rvalue; + then { + return Some(format!("{}.hypot({})", Sugg::hir(cx, &largs[0], ".."), Sugg::hir(cx, &rargs[0], ".."))); + } + } + } + + None +} + +fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { + if let Some(message) = detect_hypot(cx, args) { + span_lint_and_sugg( + cx, + IMPRECISE_FLOPS, + expr.span, + "hypotenuse can be computed more accurately", + "consider using", + message, + Applicability::MachineApplicable, + ); + } +} + // 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<'_>) { @@ -344,6 +459,14 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { rhs, ) = &expr.kind { + if let Some(parent) = get_parent_expr(cx, expr) { + if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, _, args, _) = parent.kind { + if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() { + return; + } + } + } + let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) { (inner_lhs, inner_rhs, rhs) } else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) { @@ -479,6 +602,100 @@ 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; + 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() == 2 && are_exprs_equal(cx, &args_a[1], &args_b[1]) + ); + } + } + + false +} + +fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) { + // check if expression of the form x.logN() / y.logN() + if_chain! { + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Div, .. + }, + lhs, + 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; + 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[0], ".."), Sugg::hir(cx, &rargs[0], ".."),), + Applicability::MachineApplicable, + ); + } + } +} + +fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { + if_chain! { + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Div, .. + }, + div_lhs, + div_rhs, + ) = &expr.kind; + if let ExprKind::Binary( + Spanned { + node: BinOpKind::Mul, .. + }, + mul_lhs, + mul_rhs, + ) = &div_lhs.kind; + if let Some((rvalue, _)) = constant(cx, cx.tables(), div_rhs); + if let Some((lvalue, _)) = constant(cx, cx.tables(), 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) + { + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "conversion to degrees can be done more accurately", + "consider using", + format!("{}.to_degrees()", Sugg::hir(cx, &mul_lhs, "..")), + 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 radians can be done more accurately", + "consider using", + format!("{}.to_radians()", Sugg::hir(cx, &mul_lhs, "..")), + Applicability::MachineApplicable, + ); + } + } + } +} + 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 { @@ -489,6 +706,8 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { "ln" => check_ln1p(cx, expr, args), "log" => check_log_base(cx, expr, args), "powf" => check_powf(cx, expr, args), + "powi" => check_powi(cx, expr, args), + "sqrt" => check_hypot(cx, expr, args), _ => {}, } } @@ -496,6 +715,8 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { check_expm1(cx, expr); check_mul_add(cx, expr); check_custom_abs(cx, expr); + check_log_division(cx, expr); + check_radians(cx, expr); } } } 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/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index f911cb68ea5..fbd2eeacc6e 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -135,13 +135,10 @@ 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..1b09328ceab 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -302,16 +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, ..) => { - if let Some(principal) = tt.principal() { - cx.tcx - .associated_items(principal.def_id()) - .in_definition_order() - .any(|item| is_is_empty(cx, &item)) - } else { - false - } - }, + 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/let_and_return.rs b/clippy_lints/src/let_and_return.rs index ddc41f89f8d..fa560ffb980 100644 --- a/clippy_lints/src/let_and_return.rs +++ b/clippy_lints/src/let_and_return.rs @@ -1,6 +1,5 @@ use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{Block, Expr, ExprKind, PatKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -9,7 +8,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::{in_macro, match_qpath, snippet_opt, span_lint_and_then}; +use crate::utils::{fn_def_id, in_macro, match_qpath, snippet_opt, span_lint_and_then}; declare_clippy_lint! { /// **What it does:** Checks for `let`-bindings, which are subsequently @@ -97,22 +96,6 @@ struct BorrowVisitor<'a, 'tcx> { borrows: bool, } -impl BorrowVisitor<'_, '_> { - fn fn_def_id(&self, expr: &Expr<'_>) -> Option { - match &expr.kind { - ExprKind::MethodCall(..) => self.cx.tables().type_dependent_def_id(expr.hir_id), - ExprKind::Call( - Expr { - kind: ExprKind::Path(qpath), - .. - }, - .., - ) => self.cx.qpath_res(qpath, expr.hir_id).opt_def_id(), - _ => None, - } - } -} - impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> { type Map = Map<'tcx>; @@ -121,7 +104,7 @@ impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> { return; } - if let Some(def_id) = self.fn_def_id(expr) { + if let Some(def_id) = fn_def_id(self.cx, expr) { self.borrows = self .cx .tcx diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 501220f28e5..32e79317f82 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -229,6 +229,7 @@ mod main_recursion; mod manual_async_fn; mod manual_non_exhaustive; mod map_clone; +mod map_identity; mod map_unit_fn; mod match_on_vec_items; mod matches; @@ -263,10 +264,12 @@ mod non_copy_const; mod non_expressive_names; mod open_options; mod option_env_unwrap; +mod option_if_let_else; mod overflow_check_conditional; mod panic_unimplemented; mod partialeq_ne_impl; mod path_buf_push_overwrite; +mod pattern_type_mismatch; mod precedence; mod ptr; mod ptr_offset_with_cast; @@ -274,11 +277,11 @@ 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; mod regex; +mod repeat_once; mod returns; mod serde_api; mod shadow; @@ -459,7 +462,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ); store.register_removed( "clippy::replace_consts", - "associated-constants `MIN`/`MAX` of integers are prefer to `{min,max}_value()` and module constants", + "associated-constants `MIN`/`MAX` of integers are prefered to `{min,max}_value()` and module constants", + ); + store.register_removed( + "clippy::regex_macro", + "the regex! macro has been removed from the regex crate in 2018", ); // end deprecated lints, do not remove this comment, it’s used in `update_lints` @@ -473,6 +480,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &assign_ops::ASSIGN_OP_PATTERN, &assign_ops::MISREFACTORED_ASSIGN_OP, &atomic_ordering::INVALID_ATOMIC_ORDERING, + &attrs::BLANKET_CLIPPY_RESTRICTION_LINTS, &attrs::DEPRECATED_CFG_ATTR, &attrs::DEPRECATED_SEMVER, &attrs::EMPTY_LINE_AFTER_OUTER_ATTR, @@ -608,17 +616,20 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &manual_async_fn::MANUAL_ASYNC_FN, &manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, &map_clone::MAP_CLONE, + &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_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, @@ -726,6 +737,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &non_expressive_names::SIMILAR_NAMES, &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_unimplemented::PANIC, &panic_unimplemented::PANIC_PARAMS, @@ -734,6 +746,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &panic_unimplemented::UNREACHABLE, &partialeq_ne_impl::PARTIALEQ_NE_IMPL, &path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE, + &pattern_type_mismatch::PATTERN_TYPE_MISMATCH, &precedence::PRECEDENCE, &ptr::CMP_NULL, &ptr::MUT_FROM_REF, @@ -746,14 +759,13 @@ 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, &reference::REF_IN_DEREF, ®ex::INVALID_REGEX, - ®ex::REGEX_MACRO, ®ex::TRIVIAL_REGEX, + &repeat_once::REPEAT_ONCE, &returns::NEEDLESS_RETURN, &returns::UNUSED_UNIT, &serde_api::SERDE_API_MISUSE, @@ -946,7 +958,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; @@ -990,7 +1001,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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); - store.register_late_pass(|| box trait_bounds::TraitBounds); + let max_trait_bounds = conf.max_trait_bounds; + store.register_late_pass(move || box trait_bounds::TraitBounds::new(max_trait_bounds)); store.register_late_pass(|| box comparison_chain::ComparisonChain); store.register_late_pass(|| box mut_key::MutableKeyType); store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic); @@ -1027,7 +1039,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: let array_size_threshold = conf.array_size_threshold; store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold)); store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold)); - store.register_late_pass(move || box floating_point_arithmetic::FloatingPointArithmetic); + store.register_late_pass(|| box floating_point_arithmetic::FloatingPointArithmetic); store.register_early_pass(|| box as_conversions::AsConversions); store.register_early_pass(|| box utils::internal_lints::ProduceIce); store.register_late_pass(|| box let_underscore::LetUnderscore); @@ -1043,6 +1055,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default()); store.register_late_pass(|| box unnamed_address::UnnamedAddress); store.register_late_pass(|| box dereference::Dereferencing); + store.register_late_pass(|| box option_if_let_else::OptionIfLetElse); store.register_late_pass(|| box future_not_send::FutureNotSend); store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls); store.register_late_pass(|| box if_let_mutex::IfLetMutex); @@ -1057,6 +1070,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: }); store.register_early_pass(|| box unnested_or_patterns::UnnestedOrPatterns); 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 repeat_once::RepeatOnce); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), @@ -1090,6 +1106,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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(&shadow::SHADOW_REUSE), LintId::of(&shadow::SHADOW_SAME), LintId::of(&strings::STRING_ADD), @@ -1146,6 +1163,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&needless_continue::NEEDLESS_CONTINUE), 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(&ranges::RANGE_MINUS_ONE), LintId::of(&ranges::RANGE_PLUS_ONE), LintId::of(&shadow::SHADOW_UNRELATED), LintId::of(&strings::STRING_ADD_ASSIGN), @@ -1186,6 +1205,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&assign_ops::ASSIGN_OP_PATTERN), LintId::of(&assign_ops::MISREFACTORED_ASSIGN_OP), 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), @@ -1273,13 +1293,16 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&manual_async_fn::MANUAL_ASYNC_FN), LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), 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), @@ -1364,18 +1387,16 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&ptr::PTR_ARG), LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), LintId::of(&question_mark::QUESTION_MARK), - LintId::of(&ranges::RANGE_MINUS_ONE), LintId::of(&ranges::RANGE_ZIP_WITH_LEN), 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), LintId::of(®ex::INVALID_REGEX), - LintId::of(®ex::REGEX_MACRO), LintId::of(®ex::TRIVIAL_REGEX), + LintId::of(&repeat_once::REPEAT_ONCE), LintId::of(&returns::NEEDLESS_RETURN), LintId::of(&returns::UNUSED_UNIT), LintId::of(&serde_api::SERDE_API_MISUSE), @@ -1437,6 +1458,7 @@ 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(&attrs::UNKNOWN_CLIPPY_LINTS), LintId::of(&bit_mask::VERBOSE_BIT_MASK), LintId::of(&blacklisted_name::BLACKLISTED_NAME), @@ -1470,8 +1492,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), @@ -1508,9 +1532,7 @@ 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::REGEX_MACRO), LintId::of(®ex::TRIVIAL_REGEX), LintId::of(&returns::NEEDLESS_RETURN), LintId::of(&returns::UNUSED_UNIT), @@ -1550,6 +1572,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&loops::EXPLICIT_COUNTER_LOOP), LintId::of(&loops::MUT_RANGE_BOUND), LintId::of(&loops::WHILE_LET_LOOP), + 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), @@ -1580,10 +1603,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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_MINUS_ONE), LintId::of(&ranges::RANGE_ZIP_WITH_LEN), LintId::of(&reference::DEREF_ADDROF), LintId::of(&reference::REF_IN_DEREF), + LintId::of(&repeat_once::REPEAT_ONCE), LintId::of(&swap::MANUAL_SWAP), LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT), LintId::of(&transmute::CROSSPOINTER_TRANSMUTE), 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/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 7ba43562d7d..a36fdca5d5d 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -264,10 +264,13 @@ 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..396bb659109 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -686,13 +686,9 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { NeverLoopResult::AlwaysBreak } }, - 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 - } - }, + 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() @@ -1881,13 +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) => { - if let Some(val) = n.try_eval_usize(cx.tcx, cx.param_env) { - (0..=32).contains(&val) - } else { - false - } - }, + ty::Array(_, n) => 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,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 = if let Some(ref init) = local.init { + 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 - } + }) } } } @@ -2105,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/map_identity.rs b/clippy_lints/src/map_identity.rs new file mode 100644 index 00000000000..24ec78c8846 --- /dev/null +++ b/clippy_lints/src/map_identity.rs @@ -0,0 +1,126 @@ +use crate::utils::{ + is_adjusted, is_type_diagnostic_item, match_path, match_trait_method, match_var, paths, remove_blocks, + span_lint_and_sugg, +}; +use if_chain::if_chain; +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}; + +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(ref method, _, ref args, _) = expr.kind; + if args.len() == 2 && method.ident.as_str() == "map"; + let caller_ty = cx.tables().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)); + then { + Some(args) + } else { + None + } + } +} + +/// Checks if an expression represents the identity function +/// Only examines closures and `std::convert::identity` +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), + _ => false, + } +} + +/// Checks if a function's body represents the identity function +/// Looks for bodies of the form `|x| x`, `|x| return x`, `|x| { return x }` or `|x| { +/// return x; }` +fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { + let params = func.params; + let body = remove_blocks(&func.value); + + // if there's less/more than one parameter, then it is not the identity function + if params.len() != 1 { + return false; + } + + 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, _) => { + 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; + then { + match_expr_param(cx, ret_val, params[0].pat) + } else { + false + } + } + }, + _ => false, + } +} + +/// Returns true iff an expression returns the same thing as a parameter's pattern +fn match_expr_param(cx: &LateContext<'_>, expr: &Expr<'_>, pat: &Pat<'_>) -> bool { + if let PatKind::Binding(_, _, ident, _) = pat.kind { + match_var(expr, ident.name) && !(cx.tables().hir_owner == expr.hir_id.owner && is_adjusted(cx, expr)) + } else { + false + } +} diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index b754a45aa40..bd474c20807 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -13,14 +13,14 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::CtorKind; use rustc_hir::{ - Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Local, MatchSource, Mutability, Node, Pat, PatKind, - QPath, RangeEnd, + Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Guard, Local, MatchSource, Mutability, Node, Pat, + PatKind, QPath, RangeEnd, }; 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_span::source_map::Span; +use rustc_span::source_map::{Span, Spanned}; use std::cmp::Ordering; use std::collections::Bound; @@ -409,6 +409,74 @@ declare_clippy_lint! { "a match on a struct that binds all fields but still uses the wildcard pattern" } +declare_clippy_lint! { + /// **What it does:** Lint for redundant pattern matching over `Result` or + /// `Option` + /// + /// **Why is this bad?** It's more concise and clear to just use the proper + /// utility function + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// if let Ok(_) = Ok::(42) {} + /// if let Err(_) = Err::(42) {} + /// if let None = None::<()> {} + /// if let Some(_) = Some(42) {} + /// match Ok::(42) { + /// Ok(_) => true, + /// Err(_) => false, + /// }; + /// ``` + /// + /// The more idiomatic use would be: + /// + /// ```rust + /// if Ok::(42).is_ok() {} + /// if Err::(42).is_err() {} + /// if None::<()>.is_none() {} + /// if Some(42).is_some() {} + /// Ok::(42).is_ok(); + /// ``` + pub REDUNDANT_PATTERN_MATCHING, + style, + "use the proper utility function avoiding an `if let`" +} + +declare_clippy_lint! { + /// **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. + /// + /// **Known problems:** None + /// + /// **Example:** + /// ```rust + /// let x = Some(5); + /// + /// // Bad + /// let a = match x { + /// Some(0) => true, + /// _ => false, + /// }; + /// + /// let a = if let Some(0) = x { + /// true + /// } else { + /// false + /// }; + /// + /// // Good + /// let a = matches!(x, Some(0)); + /// ``` + pub MATCH_LIKE_MATCHES_MACRO, + style, + "a match that could be written with the matches! macro" +} + #[derive(Default)] pub struct Matches { infallible_destructuring_match_linted: bool, @@ -427,7 +495,9 @@ impl_lint_pass!(Matches => [ WILDCARD_IN_OR_PATTERNS, MATCH_SINGLE_BINDING, INFALLIBLE_DESTRUCTURING_MATCH, - REST_PAT_IN_FULLY_BOUND_STRUCTS + REST_PAT_IN_FULLY_BOUND_STRUCTS, + REDUNDANT_PATTERN_MATCHING, + MATCH_LIKE_MATCHES_MACRO ]); impl<'tcx> LateLintPass<'tcx> for Matches { @@ -435,6 +505,10 @@ impl<'tcx> LateLintPass<'tcx> for Matches { if in_external_macro(cx.sess(), expr.span) { return; } + + redundant_pattern_match::check(cx, expr); + check_match_like_matches(cx, expr); + if let ExprKind::Match(ref ex, ref arms, MatchSource::Normal) = expr.kind { check_single_match(cx, ex, arms, expr); check_match_bool(cx, ex, arms, expr); @@ -530,16 +604,22 @@ fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp // the lint noisy in unnecessary situations return; } - let els = remove_blocks(&arms[1].body); - let els = if is_unit_expr(els) { + let els = arms[1].body; + let els = if is_unit_expr(remove_blocks(els)) { None - } else if let ExprKind::Block(_, _) = els.kind { - // matches with blocks that contain statements are prettier as `if let + else` - Some(els) + } 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() { + // single statement/expr "else" block, don't lint + return; + } else { + // block with 2+ statements or 1 expr and 1+ statement + Some(els) + } } else { - // allow match arms with just expressions - return; + // not a block, don't lint + return; }; + let ty = cx.tables().expr_ty(ex); if ty.kind != ty::Bool || is_allowed(cx, MATCH_BOOL, ex.hir_id) { check_single_match_single_pattern(cx, ex, arms, expr, els); @@ -802,13 +882,8 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) // 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<'_>| { - if let PatKind::Wild | PatKind::Binding(.., None) = pat.kind { - true - } else { - false - } - }; + 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())); } @@ -989,6 +1064,79 @@ fn check_wild_in_or_pats(cx: &LateContext<'_>, arms: &[Arm<'_>]) { } } +/// Lint a `match` or `if let .. { .. } else { .. }` expr that could be replaced by `matches!` +fn check_match_like_matches<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let ExprKind::Match(ex, arms, ref match_source) = &expr.kind { + match match_source { + MatchSource::Normal => find_matches_sugg(cx, ex, arms, expr, false), + MatchSource::IfLetDesugar { .. } => find_matches_sugg(cx, ex, arms, expr, true), + _ => return, + } + } +} + +/// Lint a `match` or desugared `if let` for replacement by `matches!` +fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>, desugared: bool) { + if_chain! { + if arms.len() == 2; + if cx.tables().expr_ty(expr).is_bool(); + if is_wild(&arms[1].pat); + if let Some(first) = find_bool_lit(&arms[0].body.kind, desugared); + if let Some(second) = find_bool_lit(&arms[1].body.kind, desugared); + if first != second; + then { + let mut applicability = Applicability::MachineApplicable; + + let pat_and_guard = if let Some(Guard::If(g)) = arms[0].guard { + format!("{} if {}", snippet_with_applicability(cx, arms[0].pat.span, "..", &mut applicability), snippet_with_applicability(cx, g.span, "..", &mut applicability)) + } else { + format!("{}", snippet_with_applicability(cx, arms[0].pat.span, "..", &mut applicability)) + }; + span_lint_and_sugg( + cx, + MATCH_LIKE_MATCHES_MACRO, + expr.span, + &format!("{} expression looks like `matches!` macro", if desugared { "if let .. else" } else { "match" }), + "try this", + format!( + "{}matches!({}, {})", + if first { "" } else { "!" }, + snippet_with_applicability(cx, ex.span, "..", &mut applicability), + pat_and_guard, + ), + applicability, + ) + } + } +} + +/// Extract a `bool` or `{ bool }` +fn find_bool_lit(ex: &ExprKind<'_>, desugared: bool) -> Option { + match ex { + ExprKind::Lit(Spanned { + node: LitKind::Bool(b), .. + }) => Some(*b), + ExprKind::Block( + rustc_hir::Block { + stmts: &[], + expr: Some(exp), + .. + }, + _, + ) if desugared => { + if let ExprKind::Lit(Spanned { + node: LitKind::Bool(b), .. + }) = exp.kind + { + Some(b) + } else { + None + } + }, + _ => None, + } +} + 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) { return; @@ -1179,10 +1327,7 @@ fn is_unit_expr(expr: &Expr<'_>) -> bool { // Checks if arm has the form `None => None` fn is_none_arm(arm: &Arm<'_>) -> bool { - match arm.pat.kind { - PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE) => true, - _ => false, - } + matches!(arm.pat.kind, PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE)) } // Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`) @@ -1293,6 +1438,229 @@ where None } +mod redundant_pattern_match { + use super::REDUNDANT_PATTERN_MATCHING; + use crate::utils::{in_constant, match_qpath, match_trait_method, paths, snippet, span_lint_and_then}; + use if_chain::if_chain; + use rustc_ast::ast::LitKind; + use rustc_errors::Applicability; + use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, PatKind, QPath}; + use rustc_lint::LateContext; + use rustc_middle::ty; + use rustc_mir::const_eval::is_const_fn; + use rustc_span::source_map::Symbol; + + pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let ExprKind::Match(op, arms, ref match_source) = &expr.kind { + match match_source { + MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms), + MatchSource::IfLetDesugar { .. } => find_sugg_for_if_let(cx, expr, op, arms, "if"), + MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, arms, "while"), + _ => {}, + } + } + } + + fn find_sugg_for_if_let<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + op: &Expr<'_>, + arms: &[Arm<'_>], + keyword: &'static str, + ) { + fn find_suggestion(cx: &LateContext<'_>, hir_id: HirId, path: &QPath<'_>) -> Option<&'static str> { + if match_qpath(path, &paths::RESULT_OK) && can_suggest(cx, hir_id, sym!(result_type), "is_ok") { + return Some("is_ok()"); + } + if match_qpath(path, &paths::RESULT_ERR) && can_suggest(cx, hir_id, sym!(result_type), "is_err") { + return Some("is_err()"); + } + if match_qpath(path, &paths::OPTION_SOME) && can_suggest(cx, hir_id, sym!(option_type), "is_some") { + return Some("is_some()"); + } + if match_qpath(path, &paths::OPTION_NONE) && can_suggest(cx, hir_id, sym!(option_type), "is_none") { + return Some("is_none()"); + } + None + } + + let hir_id = expr.hir_id; + let good_method = match arms[0].pat.kind { + PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => { + if let PatKind::Wild = patterns[0].kind { + find_suggestion(cx, hir_id, path) + } else { + None + } + }, + PatKind::Path(ref path) => find_suggestion(cx, hir_id, path), + _ => None, + }; + let good_method = match good_method { + Some(method) => method, + None => return, + }; + + // check that `while_let_on_iterator` lint does not trigger + if_chain! { + 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); + then { + return; + } + } + + span_lint_and_then( + cx, + REDUNDANT_PATTERN_MATCHING, + arms[0].pat.span, + &format!("redundant pattern matching, consider using `{}`", good_method), + |diag| { + // while let ... = ... { ... } + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + let expr_span = expr.span; + + // while let ... = ... { ... } + // ^^^ + let op_span = op.span.source_callsite(); + + // while let ... = ... { ... } + // ^^^^^^^^^^^^^^^^^^^ + let span = expr_span.until(op_span.shrink_to_hi()); + diag.span_suggestion( + span, + "try this", + format!("{} {}.{}", keyword, snippet(cx, op_span, "_"), good_method), + Applicability::MachineApplicable, // snippet + ); + }, + ); + } + + fn find_sugg_for_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) { + if arms.len() == 2 { + let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind); + + let hir_id = expr.hir_id; + let found_good_method = match node_pair { + ( + PatKind::TupleStruct(ref path_left, ref patterns_left, _), + PatKind::TupleStruct(ref path_right, ref 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( + arms, + path_left, + path_right, + &paths::RESULT_OK, + &paths::RESULT_ERR, + "is_ok()", + "is_err()", + || can_suggest(cx, hir_id, sym!(result_type), "is_ok"), + || can_suggest(cx, hir_id, sym!(result_type), "is_err"), + ) + } else { + 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, _)) + if patterns.len() == 1 => + { + if let PatKind::Wild = patterns[0].kind { + find_good_method_for_match( + arms, + path_left, + path_right, + &paths::OPTION_SOME, + &paths::OPTION_NONE, + "is_some()", + "is_none()", + || can_suggest(cx, hir_id, sym!(option_type), "is_some"), + || can_suggest(cx, hir_id, sym!(option_type), "is_none"), + ) + } else { + None + } + }, + _ => None, + }; + + if let Some(good_method) = found_good_method { + span_lint_and_then( + cx, + REDUNDANT_PATTERN_MATCHING, + expr.span, + &format!("redundant pattern matching, consider using `{}`", good_method), + |diag| { + let span = expr.span.to(op.span); + diag.span_suggestion( + span, + "try this", + format!("{}.{}", snippet(cx, op.span, "_"), good_method), + Applicability::MaybeIncorrect, // snippet + ); + }, + ); + } + } + } + + #[allow(clippy::too_many_arguments)] + fn find_good_method_for_match<'a>( + arms: &[Arm<'_>], + path_left: &QPath<'_>, + path_right: &QPath<'_>, + expected_left: &[&str], + expected_right: &[&str], + should_be_left: &'a str, + should_be_right: &'a str, + can_suggest_left: impl Fn() -> bool, + can_suggest_right: impl Fn() -> bool, + ) -> Option<&'a str> { + let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) { + (&(*arms[0].body).kind, &(*arms[1].body).kind) + } else if match_qpath(path_right, expected_left) && match_qpath(path_left, 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) { + (LitKind::Bool(true), LitKind::Bool(false)) if can_suggest_left() => Some(should_be_left), + (LitKind::Bool(false), LitKind::Bool(true)) if can_suggest_right() => Some(should_be_right), + _ => None, + }, + _ => None, + } + } + + fn can_suggest(cx: &LateContext<'_>, hir_id: HirId, diag_item: Symbol, name: &str) -> bool { + if !in_constant(cx, hir_id) { + return true; + } + + // Avoid suggesting calls to non-`const fn`s in const contexts, see #5697. + cx.tcx + .get_diagnostic_item(diag_item) + .and_then(|def_id| { + cx.tcx.inherent_impls(def_id).iter().find_map(|imp| { + cx.tcx + .associated_items(*imp) + .in_definition_order() + .find_map(|item| match item.kind { + ty::AssocKind::Fn if item.ident.name.as_str() == name => Some(item.def_id), + _ => None, + }) + }) + }) + .map_or(false, |def_id| is_const_fn(cx.tcx, def_id)) + } +} + #[test] fn test_overlapping() { use rustc_span::source_map::DUMMY_SP; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 216db12f011..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))); @@ -2044,7 +2038,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp } 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); } }); } @@ -2460,13 +2454,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) => { - if let Some(size) = size.try_eval_usize(cx.tcx, cx.param_env) { - size < 32 - } else { - false - } - }, + 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 fdcba110542..75e123eb593 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -77,13 +77,10 @@ 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) - } - }, + 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 0a2d577396a..c8aa98d3489 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, @@ -86,16 +86,15 @@ 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])) - } else { - None - } - } else if let Some(c) = constant_simple(cx, cx.tables(), &args[1]) { - Some((m, c, &args[0])) - } else { - None - } + constant_simple(cx, cx.tables(), &args[0]).map_or_else( + || constant_simple(cx, cx.tables(), &args[1]).map(|c| (m, c, &args[0])), + |c| { + if constant_simple(cx, cx.tables(), &args[1]).is_none() { + // otherwise ignore + Some((m, c, &args[1])) + } else { + None + } + }, + ) } diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index d7e1a62a19d..400f4b609af 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -3,11 +3,11 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt, StmtKind, Ty, - TyKind, UnOp, + self as hir, def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt, + StmtKind, TyKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::{ExpnKind, Span}; @@ -371,8 +371,8 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { if op.is_comparison() { check_nan(cx, left, expr); check_nan(cx, right, expr); - check_to_owned(cx, left, right); - check_to_owned(cx, right, left); + check_to_owned(cx, left, right, true); + check_to_owned(cx, right, left, false); } if (op == BinOpKind::Eq || op == BinOpKind::Ne) && (is_float(cx, left) || is_float(cx, right)) { if is_allowed(cx, left) || is_allowed(cx, right) { @@ -570,11 +570,30 @@ fn is_array(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { matches!(&walk_ptrs_ty(cx.tables().expr_ty(expr)).kind, ty::Array(_, _)) } -fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>) { +fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) { + #[derive(Default)] + struct EqImpl { + ty_eq_other: bool, + other_eq_ty: bool, + } + + impl EqImpl { + fn is_implemented(&self) -> bool { + self.ty_eq_other || self.other_eq_ty + } + } + + fn symmetric_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> Option { + cx.tcx.lang_items().eq_trait().map(|def_id| EqImpl { + ty_eq_other: implements_trait(cx, ty, def_id, &[other.into()]), + other_eq_ty: implements_trait(cx, other, def_id, &[ty.into()]), + }) + } + let (arg_ty, snip) = match expr.kind { ExprKind::MethodCall(.., ref args, _) if args.len() == 1 => { if match_trait_method(cx, expr, &paths::TO_STRING) || match_trait_method(cx, expr, &paths::TO_OWNED) { - (cx.tables().expr_ty_adjusted(&args[0]), snippet(cx, args[0].span, "..")) + (cx.tables().expr_ty(&args[0]), snippet(cx, args[0].span, "..")) } else { return; } @@ -582,7 +601,7 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>) { ExprKind::Call(ref path, ref 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.tables().expr_ty_adjusted(&v[0]), snippet(cx, v[0].span, "..")) + (cx.tables().expr_ty(&v[0]), snippet(cx, v[0].span, "..")) } else { return; } @@ -593,28 +612,19 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>) { _ => return, }; - let other_ty = cx.tables().expr_ty_adjusted(other); - let partial_eq_trait_id = match cx.tcx.lang_items().eq_trait() { - Some(id) => id, - None => return, - }; + let other_ty = cx.tables().expr_ty(other); - let deref_arg_impl_partial_eq_other = arg_ty.builtin_deref(true).map_or(false, |tam| { - implements_trait(cx, tam.ty, partial_eq_trait_id, &[other_ty.into()]) - }); - let arg_impl_partial_eq_deref_other = other_ty.builtin_deref(true).map_or(false, |tam| { - implements_trait(cx, arg_ty, partial_eq_trait_id, &[tam.ty.into()]) - }); - let arg_impl_partial_eq_other = implements_trait(cx, arg_ty, partial_eq_trait_id, &[other_ty.into()]); + let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default(); + let with_deref = arg_ty + .builtin_deref(true) + .and_then(|tam| symmetric_partial_eq(cx, tam.ty, other_ty)) + .unwrap_or_default(); - if !deref_arg_impl_partial_eq_other && !arg_impl_partial_eq_deref_other && !arg_impl_partial_eq_other { + if !with_deref.is_implemented() && !without_deref.is_implemented() { return; } - let other_gets_derefed = match other.kind { - ExprKind::Unary(UnOp::UnDeref, _) => true, - _ => false, - }; + let other_gets_derefed = matches!(other.kind, ExprKind::Unary(UnOp::UnDeref, _)); let lint_span = if other_gets_derefed { expr.span.to(other.span) @@ -634,18 +644,34 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>) { return; } - let try_hint = if deref_arg_impl_partial_eq_other { - // suggest deref on the left - format!("*{}", snip) + let expr_snip; + let eq_impl; + if with_deref.is_implemented() { + expr_snip = format!("*{}", snip); + eq_impl = with_deref; } else { - // suggest dropping the to_owned on the left - snip.to_string() + expr_snip = snip.to_string(); + eq_impl = without_deref; }; + let span; + let hint; + if (eq_impl.ty_eq_other && left) || (eq_impl.other_eq_ty && !left) { + span = expr.span; + hint = expr_snip; + } else { + span = expr.span.to(other.span); + if eq_impl.ty_eq_other { + hint = format!("{} == {}", expr_snip, snippet(cx, other.span, "..")); + } else { + hint = format!("{} == {}", snippet(cx, other.span, ".."), expr_snip); + } + } + diag.span_suggestion( - lint_span, + span, "try", - try_hint, + hint, Applicability::MachineApplicable, // snippet ); }, @@ -656,16 +682,10 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>) { /// `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 { - ExprKind::Assign(_, ref rhs, _) | ExprKind::AssignOp(_, _, ref rhs) => { - SpanlessEq::new(cx).eq_expr(rhs, expr) - }, - _ => is_used(cx, parent), - } - } else { - true - } + 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), + }) } /// Tests whether an expression is in a macro expansion (e.g., something @@ -674,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 } @@ -694,7 +709,7 @@ fn non_macro_local(cx: &LateContext<'_>, res: def::Res) -> bool { } } -fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &Ty<'_>) { +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; 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/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs new file mode 100644 index 00000000000..8dbe58763bf --- /dev/null +++ b/clippy_lints/src/option_if_let_else.rs @@ -0,0 +1,267 @@ +use crate::utils; +use crate::utils::sugg::Sugg; +use crate::utils::{match_type, paths, span_lint_and_sugg}; +use if_chain::if_chain; + +use rustc_errors::Applicability; +use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; +use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, MatchSource, Mutability, PatKind, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; +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). + /// + /// **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 + /// 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:** + /// + /// ```rust + /// # let optional: Option = Some(0); + /// # fn do_complicated_function() -> u32 { 5 }; + /// let _ = if let Some(foo) = optional { + /// foo + /// } else { + /// 5 + /// }; + /// let _ = if let Some(foo) = optional { + /// foo + /// } else { + /// let y = do_complicated_function(); + /// y*y + /// }; + /// ``` + /// + /// should be + /// + /// ```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(); + /// y*y + /// }, |foo| foo); + /// ``` + pub OPTION_IF_LET_ELSE, + pedantic, + "reimplementation of Option::map_or" +} + +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" && match_type(cx, &cx.tables().expr_ty(&receiver), &paths::RESULT) + } else { + false + } +} + +/// A struct containing information about occurences of the +/// `if let Some(..) = .. else` construct that this lint detects. +struct OptionIfLetElseOccurence { + option: String, + method_sugg: String, + some_expr: String, + none_expr: String, + wrap_braces: bool, +} + +struct ReturnBreakContinueMacroVisitor { + seen_return_break_continue: bool, +} +impl ReturnBreakContinueMacroVisitor { + fn new() -> ReturnBreakContinueMacroVisitor { + ReturnBreakContinueMacroVisitor { + seen_return_break_continue: false, + } + } +} +impl<'tcx> Visitor<'tcx> for ReturnBreakContinueMacroVisitor { + type Map = Map<'tcx>; + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { + if self.seen_return_break_continue { + // No need to look farther if we've already seen one of them + return; + } + match &ex.kind { + ExprKind::Ret(..) | ExprKind::Break(..) | ExprKind::Continue(..) => { + self.seen_return_break_continue = true; + }, + // 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 utils::in_macro(ex.span) { + self.seen_return_break_continue = true; + } else { + rustc_hir::intravisit::walk_expr(self, ex); + } + }, + } + } +} + +fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool { + let mut recursive_visitor = ReturnBreakContinueMacroVisitor::new(); + recursive_visitor.visit_expr(expression); + recursive_visitor.seen_return_break_continue +} + +/// Extracts the body of a given arm. If the arm contains only an expression, +/// then it returns the expression. Otherwise, it returns the entire block +fn extract_body_from_arm<'a>(arm: &'a Arm<'a>) -> Option<&'a Expr<'a>> { + if let ExprKind::Block( + Block { + stmts: statements, + expr: Some(expr), + .. + }, + _, + ) = &arm.body.kind + { + if let [] = statements { + Some(&expr) + } else { + Some(&arm.body) + } + } else { + None + } +} + +/// If this is the else body of an if/else expression, then we need to wrap +/// it in curcly 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 { + kind: + ExprKind::Match( + _, + arms, + MatchSource::IfDesugar { + contains_else_clause: true, + } + | MatchSource::IfLetDesugar { + contains_else_clause: true, + }, + ), + .. + }) = parent.expr + { + expr.hir_id == arms[1].body.hir_id + } else { + false + } + }) +} + +fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: bool, as_mut: bool) -> String { + format!( + "{}{}", + Sugg::hir(cx, cond_expr, "..").maybe_par(), + if as_mut { + ".as_mut()" + } else if as_ref { + ".as_ref()" + } else { + "" + } + ) +} + +/// 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 { + 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; + 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 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); + then { + let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" }; + let some_body = extract_body_from_arm(&arms[0])?; + let none_body = extract_body_from_arm(&arms[1])?; + let method_sugg = match &none_body.kind { + ExprKind::Block(..) => "map_or_else", + _ => "map_or", + }; + 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 { + ExprKind::AddrOf(_, Mutability::Not, _) => (true, false), + ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true), + _ => (bind_annotation == &BindingAnnotation::Ref, bind_annotation == &BindingAnnotation::RefMut), + }; + let cond_expr = match &cond_expr.kind { + // Pointer dereferencing happens automatically, so we can omit it in the suggestion + ExprKind::Unary(UnOp::UnDeref, expr) | ExprKind::AddrOf(_, _, expr) => expr, + _ => cond_expr, + }; + Some(OptionIfLetElseOccurence { + 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(cx, some_body, "..")), + none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir(cx, none_body, "..")), + wrap_braces, + }) + } else { + None + } + } +} + +impl<'a> LateLintPass<'a> for OptionIfLetElse { + fn check_expr(&mut self, cx: &LateContext<'a>, expr: &Expr<'_>) { + if let Some(detection) = detect_option_if_let_else(cx, expr) { + span_lint_and_sugg( + cx, + OPTION_IF_LET_ELSE, + expr.span, + format!("use Option::{} instead of an if let/else", detection.method_sugg).as_str(), + "try", + format!( + "{}{}.{}({}, {}){}", + if detection.wrap_braces { "{ " } else { "" }, + detection.option, + detection.method_sugg, + detection.none_expr, + detection.some_expr, + if detection.wrap_braces { " }" } else { "" }, + ), + Applicability::MaybeIncorrect, + ); + } + } +} diff --git a/clippy_lints/src/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs new file mode 100644 index 00000000000..a49dc87c0b4 --- /dev/null +++ b/clippy_lints/src/pattern_type_mismatch.rs @@ -0,0 +1,311 @@ +use crate::utils::{last_path_segment, span_lint_and_help}; +use rustc_hir::{ + intravisit, Body, Expr, ExprKind, FieldPat, FnDecl, HirId, LocalSource, MatchSource, Mutability, Pat, PatKind, + QPath, Stmt, StmtKind, +}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::{AdtDef, FieldDef, Ty, TyKind, VariantDef}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::source_map::Span; + +declare_clippy_lint! { + /// **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 + /// against or the pattern itself, as well as the bindings that are introduced by the + /// adjusted patterns. For matching you will have to either dereference the expression + /// with the `*` operator, or amend the patterns to explicitly match against `&` + /// or `&mut ` depending on the reference mutability. For the bindings you need + /// to use the inverse. You can leave them as plain bindings if you wish for the value + /// to be copied, but you must use `ref mut ` or `ref ` to construct + /// a reference into the matched structure. + /// + /// If you are looking for a way to learn about ownership semantics in more detail, it + /// is recommended to look at IDE options available to you to highlight types, lifetimes + /// and reference semantics in your code. The available tooling would expose these things + /// in a general way even outside of the various pattern matching mechanics. Of course + /// 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 + /// in ownership. + /// + /// **Known problems:** None. + /// + /// **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`. + /// + /// ```rust,ignore + /// // Bad + /// let value = &Some(Box::new(23)); + /// match value { + /// Some(inner) => println!("{}", inner), + /// None => println!("none"), + /// } + /// + /// // Good + /// let value = &Some(Box::new(23)); + /// match *value { + /// Some(ref inner) => println!("{}", inner), + /// None => println!("none"), + /// } + /// ``` + /// + /// The following example demonstrates one of the advantages of the more verbose style. + /// Note how the second version uses `ref mut a` to explicitly declare `a` a shared mutable + /// borrow, while `b` is simply taken by value. This ensures that the loop body cannot + /// accidentally modify the wrong part of the structure. + /// + /// ```rust,ignore + /// // Bad + /// let mut values = vec![(2, 3), (3, 4)]; + /// for (a, b) in &mut values { + /// *a += *b; + /// } + /// + /// // Good + /// let mut values = vec![(2, 3), (3, 4)]; + /// for &mut (ref mut a, b) in &mut values { + /// *a += b; + /// } + /// ``` + pub PATTERN_TYPE_MISMATCH, + restriction, + "type of pattern does not match the expression type" +} + +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 Some(init) = &local.init { + if let Some(init_ty) = cx.tables().node_type_opt(init.hir_id) { + let pat = &local.pat; + if in_external_macro(cx.sess(), pat.span) { + return; + } + let deref_possible = match local.source { + LocalSource::Normal => DerefPossible::Possible, + _ => DerefPossible::Impossible, + }; + apply_lint(cx, pat, init_ty, deref_possible); + } + } + } + } + + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if let ExprKind::Match(ref expr, arms, source) = expr.kind { + match source { + MatchSource::Normal | MatchSource::IfLetDesugar { .. } | MatchSource::WhileLetDesugar => { + if let Some(expr_ty) = cx.tables().node_type_opt(expr.hir_id) { + 'pattern_checks: for arm in arms { + let pat = &arm.pat; + if in_external_macro(cx.sess(), pat.span) { + continue 'pattern_checks; + } + if apply_lint(cx, pat, expr_ty, DerefPossible::Possible) { + break 'pattern_checks; + } + } + } + }, + _ => (), + } + } + } + + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + _: intravisit::FnKind<'tcx>, + _: &'tcx FnDecl<'_>, + body: &'tcx Body<'_>, + _: Span, + hir_id: HirId, + ) { + if let Some(fn_sig) = cx.tables().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); + } + } + } +} + +#[derive(Debug, Clone, Copy)] +enum DerefPossible { + Possible, + Impossible, +} + +fn apply_lint<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, expr_ty: Ty<'tcx>, deref_possible: DerefPossible) -> bool { + let maybe_mismatch = find_first_mismatch(cx, pat, expr_ty, Level::Top); + if let Some((span, mutability, level)) = maybe_mismatch { + span_lint_and_help( + cx, + PATTERN_TYPE_MISMATCH, + span, + "type of pattern does not match the expression type", + None, + &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 ", + _ => "", + }, + match mutability { + Mutability::Mut => "&mut _", + Mutability::Not => "&_", + }, + ), + ); + true + } else { + false + } +} + +#[derive(Debug, Copy, Clone)] +enum Level { + Top, + Lower, +} + +#[allow(rustc::usage_of_ty_tykind)] +fn find_first_mismatch<'tcx>( + cx: &LateContext<'tcx>, + pat: &Pat<'_>, + ty: Ty<'tcx>, + level: Level, +) -> Option<(Span, Mutability, Level)> { + if let PatKind::Ref(ref sub_pat, _) = pat.kind { + if let TyKind::Ref(_, sub_ty, _) = ty.kind { + return find_first_mismatch(cx, sub_pat, sub_ty, Level::Lower); + } + } + + if let TyKind::Ref(_, _, mutability) = ty.kind { + if is_non_ref_pattern(&pat.kind) { + return Some((pat.span, mutability, level)); + } + } + + 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 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); + } + } + } + + if let PatKind::TupleStruct(ref qpath, ref pats, _) = pat.kind { + if let TyKind::Adt(ref adt_def, ref 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)); + return find_first_mismatch_in_tuple(cx, pats, ty_iter); + } + } + } + + if let PatKind::Tuple(ref pats, _) = pat.kind { + if let TyKind::Tuple(..) = ty.kind { + return find_first_mismatch_in_tuple(cx, pats, ty.tuple_fields()); + } + } + + if let PatKind::Or(sub_pats) = pat.kind { + for pat in sub_pats { + let maybe_mismatch = find_first_mismatch(cx, pat, ty, level); + if let Some(mismatch) = maybe_mismatch { + return Some(mismatch); + } + } + } + + None +} + +fn get_variant<'a>(adt_def: &'a AdtDef, qpath: &QPath<'_>) -> Option<&'a VariantDef> { + if adt_def.is_struct() { + if let Some(variant) = adt_def.variants.iter().next() { + return Some(variant); + } + } + + if adt_def.is_enum() { + let pat_ident = last_path_segment(qpath).ident; + for variant in &adt_def.variants { + if variant.ident == pat_ident { + return Some(variant); + } + } + } + + None +} + +fn find_first_mismatch_in_tuple<'tcx, I>( + cx: &LateContext<'tcx>, + pats: &[&Pat<'_>], + ty_iter_src: I, +) -> Option<(Span, Mutability, Level)> +where + I: IntoIterator>, +{ + let mut field_tys = ty_iter_src.into_iter(); + 'fields: for pat in pats { + let field_ty = if let Some(ty) = field_tys.next() { + ty + } else { + break 'fields; + }; + + let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower); + if let Some(mismatch) = maybe_mismatch { + return Some(mismatch); + } + } + + None +} + +fn find_first_mismatch_in_struct<'tcx>( + cx: &LateContext<'tcx>, + field_pats: &[FieldPat<'_>], + field_defs: &[FieldDef], + substs_ref: SubstsRef<'tcx>, +) -> Option<(Span, Mutability, Level)> { + for field_pat in field_pats { + 'definitions: for field_def in field_defs { + if field_pat.ident == field_def.ident { + let field_ty = field_def.ty(cx.tcx, substs_ref); + let pat = &field_pat.pat; + let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower); + if let Some(mismatch) = maybe_mismatch { + return Some(mismatch); + } + break 'definitions; + } + } + } + + None +} + +fn is_non_ref_pattern(pat_kind: &PatKind<'_>) -> bool { + match pat_kind { + PatKind::Struct(..) | PatKind::Tuple(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => true, + PatKind::Or(sub_pats) => sub_pats.iter().any(|pat| is_non_ref_pattern(&pat.kind)), + _ => false, + } +} diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index 23793678fa0..4797771e7bd 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/ranges.rs b/clippy_lints/src/ranges.rs index c164ec9aaf1..dd608de5723 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -52,6 +52,11 @@ declare_clippy_lint! { /// exclusive ranges, because they essentially add an extra branch that /// LLVM may fail to hoist out of the loop. /// + /// 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:** /// ```rust,ignore /// for x..(y+1) { .. } @@ -72,7 +77,10 @@ declare_clippy_lint! { /// **Why is this bad?** The code is more readable with an exclusive range /// like `x..y`. /// - /// **Known problems:** None. + /// **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:** /// ```rust,ignore @@ -83,7 +91,7 @@ declare_clippy_lint! { /// for x..y { .. } /// ``` pub RANGE_MINUS_ONE, - complexity, + pedantic, "`x..=(y-1)` reads better as `x..y`" } diff --git a/clippy_lints/src/redundant_pattern_matching.rs b/clippy_lints/src/redundant_pattern_matching.rs deleted file mode 100644 index d8d16efb978..00000000000 --- a/clippy_lints/src/redundant_pattern_matching.rs +++ /dev/null @@ -1,260 +0,0 @@ -use crate::utils::{in_constant, match_qpath, match_trait_method, paths, snippet, span_lint_and_then}; -use if_chain::if_chain; -use rustc_ast::ast::LitKind; -use rustc_errors::Applicability; -use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, PatKind, QPath}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; -use rustc_mir::const_eval::is_const_fn; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Symbol; - -declare_clippy_lint! { - /// **What it does:** Lint for redundant pattern matching over `Result` or - /// `Option` - /// - /// **Why is this bad?** It's more concise and clear to just use the proper - /// utility function - /// - /// **Known problems:** None. - /// - /// **Example:** - /// - /// ```rust - /// if let Ok(_) = Ok::(42) {} - /// if let Err(_) = Err::(42) {} - /// if let None = None::<()> {} - /// if let Some(_) = Some(42) {} - /// match Ok::(42) { - /// Ok(_) => true, - /// Err(_) => false, - /// }; - /// ``` - /// - /// The more idiomatic use would be: - /// - /// ```rust - /// if Ok::(42).is_ok() {} - /// if Err::(42).is_err() {} - /// if None::<()>.is_none() {} - /// if Some(42).is_some() {} - /// Ok::(42).is_ok(); - /// ``` - pub REDUNDANT_PATTERN_MATCHING, - style, - "use the proper utility function avoiding an `if let`" -} - -declare_lint_pass!(RedundantPatternMatching => [REDUNDANT_PATTERN_MATCHING]); - -impl<'tcx> LateLintPass<'tcx> for RedundantPatternMatching { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Match(op, arms, ref match_source) = &expr.kind { - match match_source { - MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms), - MatchSource::IfLetDesugar { .. } => find_sugg_for_if_let(cx, expr, op, arms, "if"), - MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, arms, "while"), - _ => return, - } - } - } -} - -fn find_sugg_for_if_let<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx Expr<'_>, - op: &Expr<'_>, - arms: &[Arm<'_>], - keyword: &'static str, -) { - fn find_suggestion(cx: &LateContext<'_>, hir_id: HirId, path: &QPath<'_>) -> Option<&'static str> { - if match_qpath(path, &paths::RESULT_OK) && can_suggest(cx, hir_id, sym!(result_type), "is_ok") { - return Some("is_ok()"); - } - if match_qpath(path, &paths::RESULT_ERR) && can_suggest(cx, hir_id, sym!(result_type), "is_err") { - return Some("is_err()"); - } - if match_qpath(path, &paths::OPTION_SOME) && can_suggest(cx, hir_id, sym!(option_type), "is_some") { - return Some("is_some()"); - } - if match_qpath(path, &paths::OPTION_NONE) && can_suggest(cx, hir_id, sym!(option_type), "is_none") { - return Some("is_none()"); - } - None - } - - let hir_id = expr.hir_id; - let good_method = match arms[0].pat.kind { - PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => { - if let PatKind::Wild = patterns[0].kind { - find_suggestion(cx, hir_id, path) - } else { - None - } - }, - PatKind::Path(ref path) => find_suggestion(cx, hir_id, path), - _ => None, - }; - let good_method = match good_method { - Some(method) => method, - None => return, - }; - - // check that `while_let_on_iterator` lint does not trigger - if_chain! { - 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); - then { - return; - } - } - - span_lint_and_then( - cx, - REDUNDANT_PATTERN_MATCHING, - arms[0].pat.span, - &format!("redundant pattern matching, consider using `{}`", good_method), - |diag| { - // while let ... = ... { ... } - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - let expr_span = expr.span; - - // while let ... = ... { ... } - // ^^^ - let op_span = op.span.source_callsite(); - - // while let ... = ... { ... } - // ^^^^^^^^^^^^^^^^^^^ - let span = expr_span.until(op_span.shrink_to_hi()); - diag.span_suggestion( - span, - "try this", - format!("{} {}.{}", keyword, snippet(cx, op_span, "_"), good_method), - Applicability::MachineApplicable, // snippet - ); - }, - ); -} - -fn find_sugg_for_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) { - if arms.len() == 2 { - let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind); - - let hir_id = expr.hir_id; - let found_good_method = match node_pair { - ( - PatKind::TupleStruct(ref path_left, ref patterns_left, _), - PatKind::TupleStruct(ref path_right, ref 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( - arms, - path_left, - path_right, - &paths::RESULT_OK, - &paths::RESULT_ERR, - "is_ok()", - "is_err()", - || can_suggest(cx, hir_id, sym!(result_type), "is_ok"), - || can_suggest(cx, hir_id, sym!(result_type), "is_err"), - ) - } else { - 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, _)) - if patterns.len() == 1 => - { - if let PatKind::Wild = patterns[0].kind { - find_good_method_for_match( - arms, - path_left, - path_right, - &paths::OPTION_SOME, - &paths::OPTION_NONE, - "is_some()", - "is_none()", - || can_suggest(cx, hir_id, sym!(option_type), "is_some"), - || can_suggest(cx, hir_id, sym!(option_type), "is_none"), - ) - } else { - None - } - }, - _ => None, - }; - - if let Some(good_method) = found_good_method { - span_lint_and_then( - cx, - REDUNDANT_PATTERN_MATCHING, - expr.span, - &format!("redundant pattern matching, consider using `{}`", good_method), - |diag| { - let span = expr.span.to(op.span); - diag.span_suggestion( - span, - "try this", - format!("{}.{}", snippet(cx, op.span, "_"), good_method), - Applicability::MaybeIncorrect, // snippet - ); - }, - ); - } - } -} - -#[allow(clippy::too_many_arguments)] -fn find_good_method_for_match<'a>( - arms: &[Arm<'_>], - path_left: &QPath<'_>, - path_right: &QPath<'_>, - expected_left: &[&str], - expected_right: &[&str], - should_be_left: &'a str, - should_be_right: &'a str, - can_suggest_left: impl Fn() -> bool, - can_suggest_right: impl Fn() -> bool, -) -> Option<&'a str> { - let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) { - (&(*arms[0].body).kind, &(*arms[1].body).kind) - } else if match_qpath(path_right, expected_left) && match_qpath(path_left, 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) { - (LitKind::Bool(true), LitKind::Bool(false)) if can_suggest_left() => Some(should_be_left), - (LitKind::Bool(false), LitKind::Bool(true)) if can_suggest_right() => Some(should_be_right), - _ => None, - }, - _ => None, - } -} - -fn can_suggest(cx: &LateContext<'_>, hir_id: HirId, diag_item: Symbol, name: &str) -> bool { - if !in_constant(cx, hir_id) { - return true; - } - - // Avoid suggesting calls to non-`const fn`s in const contexts, see #5697. - cx.tcx - .get_diagnostic_item(diag_item) - .and_then(|def_id| { - cx.tcx.inherent_impls(def_id).iter().find_map(|imp| { - cx.tcx - .associated_items(*imp) - .in_definition_order() - .find_map(|item| match item.kind { - ty::AssocKind::Fn if item.ident.name.as_str() == name => Some(item.def_id), - _ => None, - }) - }) - }) - .map_or(false, |def_id| is_const_fn(cx.tcx, def_id)) -} diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index b67abad6ccb..f204a0ffb2c 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -1,9 +1,9 @@ use crate::consts::{constant, Constant}; -use crate::utils::{is_expn_of, match_def_path, match_type, paths, span_lint, span_lint_and_help}; +use crate::utils::{match_def_path, paths, span_lint, span_lint_and_help}; use if_chain::if_chain; use rustc_ast::ast::{LitKind, StrStyle}; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::{Block, BorrowKind, Crate, Expr, ExprKind, HirId}; +use rustc_hir::{BorrowKind, Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{BytePos, Span}; @@ -46,66 +46,15 @@ declare_clippy_lint! { "trivial regular expressions" } -declare_clippy_lint! { - /// **What it does:** Checks for usage of `regex!(_)` which (as of now) is - /// usually slower than `Regex::new(_)` unless called in a loop (which is a bad - /// idea anyway). - /// - /// **Why is this bad?** Performance, at least for now. The macro version is - /// likely to catch up long-term, but for now the dynamic version is faster. - /// - /// **Known problems:** None. - /// - /// **Example:** - /// ```ignore - /// regex!("foo|bar") - /// ``` - pub REGEX_MACRO, - style, - "use of `regex!(_)` instead of `Regex::new(_)`" -} - #[derive(Clone, Default)] pub struct Regex { spans: FxHashSet, last: Option, } -impl_lint_pass!(Regex => [INVALID_REGEX, REGEX_MACRO, TRIVIAL_REGEX]); +impl_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]); impl<'tcx> LateLintPass<'tcx> for Regex { - fn check_crate(&mut self, _: &LateContext<'tcx>, _: &'tcx Crate<'_>) { - self.spans.clear(); - } - - fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { - if_chain! { - if self.last.is_none(); - if let Some(ref expr) = block.expr; - if match_type(cx, cx.tables().expr_ty(expr), &paths::REGEX); - if let Some(span) = is_expn_of(expr.span, "regex"); - then { - if !self.spans.contains(&span) { - span_lint( - cx, - REGEX_MACRO, - span, - "`regex!(_)` found. \ - Please use `Regex::new(_)`, which is faster for now." - ); - self.spans.insert(span); - } - self.last = Some(block.hir_id); - } - } - } - - fn check_block_post(&mut self, _: &LateContext<'tcx>, block: &'tcx Block<'_>) { - if self.last.map_or(false, |id| block.hir_id == id) { - self.last = None; - } - } - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { if let ExprKind::Call(ref fun, ref args) = expr.kind; @@ -150,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/repeat_once.rs b/clippy_lints/src/repeat_once.rs new file mode 100644 index 00000000000..a3af369e41e --- /dev/null +++ b/clippy_lints/src/repeat_once.rs @@ -0,0 +1,82 @@ +use crate::consts::{constant_context, Constant}; +use crate::utils::{in_macro, is_type_diagnostic_item, snippet, span_lint_and_sugg, walk_ptrs_ty}; +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:** 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` + /// + /// **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:** + /// + /// ```rust + /// fn main() { + /// let x = String::from("hello world").repeat(1); + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn main() { + /// let x = String::from("hello world").clone(); + /// } + /// ``` + 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(ref path, _, ref args, _) = expr.kind; + if path.ident.name == sym!(repeat); + if let Some(Constant::Int(1)) = constant_context(cx, cx.tables()).expr(&args[1]); + if !in_macro(args[0].span); + then { + let ty = walk_ptrs_ty(cx.tables().expr_ty(&args[0])); + 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, args[0].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, args[0].span, r#""...""#)), + Applicability::MachineApplicable, + ); + } else if is_type_diagnostic_item(cx, ty, sym!(string_type)) { + span_lint_and_sugg( + cx, + REPEAT_ONCE, + expr.span, + "calling `repeat(1)` on a string literal", + "consider using `.clone()` instead", + format!("{}.clone()", snippet(cx, args[0].span, r#""...""#)), + Applicability::MachineApplicable, + ); + } + } + } + } +} 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 7da47ee4ff9..194786c5c41 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -165,14 +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); - if let Some(var_ty) = var_ty { - match var_ty.kind { - ty::Adt(..) => false, - _ => true, - } - } else { - false - } + 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/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 9eb2079c3ca..0ef70311fb1 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -1,19 +1,19 @@ use crate::utils::{in_macro, snippet, snippet_with_applicability, span_lint_and_help, SpanlessHash}; +use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::{GenericBound, Generics, WherePredicate}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -#[derive(Copy, Clone)] -pub struct TraitBounds; - declare_clippy_lint! { /// **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 /// less readable than combining the bounds /// + /// **Known problems:** None. + /// /// **Example:** /// ```rust /// pub fn foo(t: T) where T: Copy, T: Clone {} @@ -29,6 +29,18 @@ declare_clippy_lint! { "Types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`" } +#[derive(Copy, Clone)] +pub struct TraitBounds { + max_trait_bounds: u64, +} + +impl TraitBounds { + #[must_use] + pub fn new(max_trait_bounds: u64) -> Self { + Self { max_trait_bounds } + } +} + impl_lint_pass!(TraitBounds => [TYPE_REPETITION_IN_BOUNDS]); impl<'tcx> LateLintPass<'tcx> for TraitBounds { @@ -44,9 +56,14 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { let mut map = FxHashMap::default(); let mut applicability = Applicability::MaybeIncorrect; for bound in gen.where_clause.predicates { - if let WherePredicate::BoundPredicate(ref p) = bound { + if_chain! { + 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); - if let Some(ref v) = map.insert(h, p.bounds.iter().collect::>()) { + if let Some(ref v) = map.insert(h, p.bounds.iter().collect::>()); + + then { let mut hint_string = format!( "consider combining the bounds: `{}:", snippet(cx, p.bounded_ty.span, "_") diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 68f51f0afdc..bca388ecdcc 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) { @@ -1205,16 +1192,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 = if let Some(ref snip) = opt { - if should_strip_parens(op, snip) { - &snip[1..snip.len() - 1] - } else { - snip.as_str() - } - } else { - applicability = Applicability::HasPlaceholders; - ".." - }; + 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, @@ -1734,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/unnecessary_sort_by.rs b/clippy_lints/src/unnecessary_sort_by.rs index d940776817c..91c1789a2ff 100644 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ b/clippy_lints/src/unnecessary_sort_by.rs @@ -5,24 +5,23 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{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::symbol::Ident; declare_clippy_lint! { /// **What it does:** - /// Detects when people use `Vec::sort_by` and pass in a function + /// 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 and a more complicated + /// 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 - /// imported by a use statement in the current frame, then a `use` - /// statement that imports it will need to be added (which this lint - /// can't do). + /// 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:** /// @@ -201,28 +200,41 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { }; 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; then { - Some(LintTrigger::Sort(SortDetection { vec_name, unstable })) - } - else { - Some(LintTrigger::SortByKey(SortByKeyDetection { - vec_name, - unstable, - closure_arg, - closure_body, - reverse - })) + return Some(LintTrigger::Sort(SortDetection { vec_name, unstable })) + } else { + if !key_returns_borrow(cx, left_expr) { + return Some(LintTrigger::SortByKey(SortByKeyDetection { + vec_name, + unstable, + closure_arg, + closure_body, + reverse + })) + } } } - } else { - None } } + + None +} + +fn key_returns_borrow(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let Some(def_id) = utils::fn_def_id(cx, expr) { + let output = cx.tcx.fn_sig(def_id).output(); + let ty = output.skip_binder(); + return matches!(ty.kind, ty::Ref(..)) + || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))); + } + + false } impl LateLintPass<'_> for UnnecessarySortBy { diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 4d3682263f1..502bf0c4279 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -72,8 +72,8 @@ impl EarlyLintPass for UnnestedOrPatterns { } fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) { - if !cx.sess.opts.unstable_features.is_nightly_build() { - // User cannot do `#![feature(or_patterns)]`, so bail. + if !cx.sess.features_untracked().or_patterns { + // Do not suggest nesting the patterns if the feature `or_patterns` is not enabled. return; } @@ -400,8 +400,8 @@ fn extend_with_matching( /// Are the patterns in `ps1` and `ps2` equal save for `ps1[idx]` compared to `ps2[idx]`? fn eq_pre_post(ps1: &[P], ps2: &[P], idx: usize) -> bool { - ps1[idx].is_rest() == ps2[idx].is_rest() // Avoid `[x, ..] | [x, 0]` => `[x, .. | 0]`. - && ps1.len() == ps2.len() + ps1.len() == ps2.len() + && ps1[idx].is_rest() == ps2[idx].is_rest() // Avoid `[x, ..] | [x, 0]` => `[x, .. | 0]`. && over(&ps1[..idx], &ps2[..idx], |l, r| eq_pat(l, r)) && over(&ps1[idx + 1..], &ps2[idx + 1..], |l, r| eq_pat(l, r)) } diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index f85db1e2006..776c6bc57ca 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -167,14 +167,11 @@ 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 { - GenericArg::Lifetime(_) => true, - _ => false, - }) - } else { - true - }; + let should_check = parameters.as_ref().map_or( + true, + |params| !params.parenthesized + &&!params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))) + ); if should_check { let visitor = &mut UseSelfVisitor { 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/attrs.rs b/clippy_lints/src/utils/attrs.rs index 4dcf6c105ec..4bb4b087c55 100644 --- a/clippy_lints/src/utils/attrs.rs +++ b/clippy_lints/src/utils/attrs.rs @@ -65,42 +65,45 @@ 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 - .iter() - .find_map(|(builtin_name, deprecation_status)| { - if *builtin_name == attr_segments[1].ident.to_string() { - Some(deprecation_status) - } else { - None + 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(); + false + }, + DeprecationStatus::None => { + diag.cancel(); + attr_segments[1].ident.to_string() == name + }, } - }) - { - 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 { - sess.span_err(attr_segments[1].ident.span, "Usage of unknown attribute"); - false - } + ) } else { false } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index c41befbf147..de425211e38 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -156,6 +156,8 @@ define_Conf! { (array_size_threshold, "array_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, "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, "max_trait_bounds": u64, 3), /// Lint: STRUCT_EXCESSIVE_BOOLS. The maximum number of bools a struct can have (max_struct_bools, "max_struct_bools": u64, 3), /// Lint: FN_PARAMS_EXCESSIVE_BOOLS. The maximum number of bools function parameters can have diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index ae58f0a1521..34341594c19 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -703,6 +703,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } for segment in path.segments { segment.ident.name.hash(&mut self.s); + self.hash_generic_args(segment.generic_args().args); } }, QPath::TypeRelative(ref ty, ref segment) => { @@ -711,13 +712,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { }, }, TyKind::OpaqueDef(_, arg_list) => { - for arg in *arg_list { - match arg { - GenericArg::Lifetime(ref l) => self.hash_lifetime(l), - GenericArg::Type(ref ty) => self.hash_ty(&ty), - GenericArg::Const(ref ca) => self.hash_body(ca.value.body), - } - } + self.hash_generic_args(arg_list); }, TyKind::TraitObject(_, lifetime) => { self.hash_lifetime(lifetime); @@ -735,4 +730,14 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_expr(&self.cx.tcx.hir().body(body_id).value); self.maybe_typeck_tables = old_maybe_typeck_tables; } + + fn hash_generic_args(&mut self, arg_list: &[GenericArg<'_>]) { + for arg in arg_list { + match arg { + GenericArg::Lifetime(ref l) => self.hash_lifetime(l), + GenericArg::Type(ref ty) => self.hash_ty(&ty), + GenericArg::Const(ref ca) => self.hash_body(ca.value.body), + } + } + } } diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 99ba7d64331..4b7a1c2b537 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. @@ -153,11 +146,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 +589,15 @@ 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) { + snippet_opt(cx, line_span).and_then(|snip| { snip.find(|c: char| !c.is_whitespace()) .map(|pos| line_span.lo() + BytePos::from_usize(pos)) - } else { - None - } + }) } /// Returns the indentation of the line of a span @@ -626,11 +609,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,25 +717,21 @@ 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 { - 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, - }, + 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, - } - } else { - None - } + }, + _ => None, + }) } /// Returns the base type for HIR references and pointers. @@ -1328,11 +1303,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 { @@ -1385,6 +1356,21 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool { ) } +/// Returns the `DefId` of the callee if the given expression is a function or method call. +pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { + match &expr.kind { + ExprKind::MethodCall(..) => cx.tables().type_dependent_def_id(expr.hir_id), + ExprKind::Call( + Expr { + kind: ExprKind::Path(qpath), + .. + }, + .., + ) => cx.tables().qpath_res(qpath, expr.hir_id).opt_def_id(), + _ => None, + } +} + pub fn run_lints(cx: &LateContext<'_>, lints: &[&'static Lint], id: HirId) -> bool { lints.iter().any(|lint| { matches!( diff --git a/clippy_lints/src/utils/numeric_literal.rs b/clippy_lints/src/utils/numeric_literal.rs index 99413153d49..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 @@ -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/paths.rs b/clippy_lints/src/utils/paths.rs index 3b7e9739211..4c3462802e9 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -98,7 +98,6 @@ pub const RANGE_TO_STD: [&str; 3] = ["std", "ops", "RangeTo"]; pub const RC: [&str; 3] = ["alloc", "rc", "Rc"]; pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"]; pub const RECEIVER: [&str; 4] = ["std", "sync", "mpsc", "Receiver"]; -pub const REGEX: [&str; 3] = ["regex", "re_unicode", "Regex"]; pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"]; pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"]; pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"]; diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index d05e81b9505..0ac7714fbeb 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -325,22 +325,22 @@ pub fn make_unop(op: &str, expr: Sugg<'_>) -> Sugg<'static> { /// parenthesis will always be added for a mix of these. pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> { /// Returns `true` if the operator is a shift operator `<<` or `>>`. - fn is_shift(op: &AssocOp) -> bool { - matches!(*op, AssocOp::ShiftLeft | AssocOp::ShiftRight) + fn is_shift(op: AssocOp) -> bool { + matches!(op, AssocOp::ShiftLeft | AssocOp::ShiftRight) } /// Returns `true` if the operator is a arithmetic operator /// (i.e., `+`, `-`, `*`, `/`, `%`). - fn is_arith(op: &AssocOp) -> bool { + fn is_arith(op: AssocOp) -> bool { matches!( - *op, + op, AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus ) } /// Returns `true` if the operator `op` needs parenthesis with the operator /// `other` in the direction `dir`. - fn needs_paren(op: &AssocOp, other: &AssocOp, dir: Associativity) -> bool { + fn needs_paren(op: AssocOp, other: AssocOp, dir: Associativity) -> bool { other.precedence() < op.precedence() || (other.precedence() == op.precedence() && ((op != other && associativity(op) != dir) @@ -349,14 +349,14 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> || is_shift(other) && is_arith(op) } - let lhs_paren = if let Sugg::BinOp(ref lop, _) = *lhs { - needs_paren(&op, lop, Associativity::Left) + let lhs_paren = if let Sugg::BinOp(lop, _) = *lhs { + needs_paren(op, lop, Associativity::Left) } else { false }; - let rhs_paren = if let Sugg::BinOp(ref rop, _) = *rhs { - needs_paren(&op, rop, Associativity::Right) + let rhs_paren = if let Sugg::BinOp(rop, _) = *rhs { + needs_paren(op, rop, Associativity::Right) } else { false }; @@ -424,13 +424,13 @@ enum Associativity { /// they are considered /// associative. #[must_use] -fn associativity(op: &AssocOp) -> Associativity { +fn associativity(op: AssocOp) -> Associativity { use rustc_ast::util::parser::AssocOp::{ Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Colon, Divide, DotDot, DotDotEq, Equal, Greater, GreaterEqual, LAnd, LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract, }; - match *op { + match op { Assign | AssignOp(_) => Associativity::Right, Add | BitAnd | BitOr | BitXor | LAnd | LOr | Multiply | As | Colon => Associativity::Both, Divide | Equal | Greater | GreaterEqual | Less | LessEqual | Modulus | NotEqual | ShiftLeft | ShiftRight @@ -492,20 +492,20 @@ 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') { - // 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 - } - } else { - None - } + }) } /// Convenience extension trait for `DiagnosticBuilder`. diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index cb769b5a2ce..063f94582b9 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, @@ -279,13 +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 = match expr { - Some(expr) => snippet_with_applicability(cx, expr.span, "v", &mut applicability), - None => { + 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, 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() { diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index edceb755180..b89a8712862 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -80,6 +80,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "blacklisted_name", }, + Lint { + name: "blanket_clippy_restriction_lints", + group: "style", + desc: "enabling the complete restriction group", + deprecation: None, + module: "attrs", + }, Lint { name: "blocks_in_if_conditions", group: "style", @@ -1144,6 +1151,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "methods", }, + Lint { + name: "map_identity", + group: "complexity", + desc: "using iterator.map(|x| x)", + deprecation: None, + module: "map_identity", + }, Lint { name: "map_unwrap_or", group: "pedantic", @@ -1165,6 +1179,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "matches", }, + Lint { + name: "match_like_matches_macro", + group: "style", + desc: "a match that could be written with the matches! macro", + deprecation: None, + module: "matches", + }, Lint { name: "match_on_vec_items", group: "pedantic", @@ -1606,6 +1627,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "option_env_unwrap", }, + Lint { + name: "option_if_let_else", + group: "pedantic", + desc: "reimplementation of Option::map_or", + deprecation: None, + module: "option_if_let_else", + }, Lint { name: "option_map_or_none", group: "style", @@ -1683,6 +1711,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "path_buf_push_overwrite", }, + Lint { + name: "pattern_type_mismatch", + group: "restriction", + desc: "type of pattern does not match the expression type", + deprecation: None, + module: "pattern_type_mismatch", + }, Lint { name: "possible_missing_comma", group: "correctness", @@ -1755,7 +1790,7 @@ pub static ref ALL_LINTS: Vec = vec![ }, Lint { name: "range_minus_one", - group: "complexity", + group: "pedantic", desc: "`x..=(y-1)` reads better as `x..y`", deprecation: None, module: "ranges", @@ -1828,7 +1863,7 @@ pub static ref ALL_LINTS: Vec = vec![ group: "style", desc: "use the proper utility function avoiding an `if let`", deprecation: None, - module: "redundant_pattern_matching", + module: "matches", }, Lint { name: "redundant_pub_crate", @@ -1852,11 +1887,11 @@ pub static ref ALL_LINTS: Vec = vec![ module: "reference", }, Lint { - name: "regex_macro", - group: "style", - desc: "use of `regex!(_)` instead of `Regex::new(_)`", + name: "repeat_once", + group: "complexity", + desc: "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` ", deprecation: None, - module: "regex", + module: "repeat_once", }, Lint { name: "rest_pat_in_fully_bound_structs", diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 368fa6a98c5..26a47d23706 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -12,19 +12,11 @@ use std::path::{Path, PathBuf}; mod cargo; fn host_lib() -> PathBuf { - if let Some(path) = option_env!("HOST_LIBS") { - PathBuf::from(path) - } else { - cargo::CARGO_TARGET_DIR.join(env!("PROFILE")) - } + option_env!("HOST_LIBS").map_or(cargo::CARGO_TARGET_DIR.join(env!("PROFILE")), PathBuf::from) } fn clippy_driver_path() -> PathBuf { - if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") { - PathBuf::from(path) - } else { - cargo::TARGET_LIB.join("clippy-driver") - } + option_env!("CLIPPY_DRIVER_PATH").map_or(cargo::TARGET_LIB.join("clippy-driver"), PathBuf::from) } // When we'll want to use `extern crate ..` for a dependency that is used diff --git a/tests/ui-cargo/multiple_crate_versions/fail/Cargo.lock b/tests/ui-cargo/multiple_crate_versions/fail/Cargo.lock new file mode 100644 index 00000000000..7e96aa36feb --- /dev/null +++ b/tests/ui-cargo/multiple_crate_versions/fail/Cargo.lock @@ -0,0 +1,109 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] +name = "bitflags" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "ctrlc" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "653abc99aa905f693d89df4797fadc08085baee379db92be9f2496cefe8a6f2c" +dependencies = [ + "kernel32-sys", + "nix", + "winapi 0.2.8", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + +[[package]] +name = "libc" +version = "0.2.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" + +[[package]] +name = "multiple_crate_versions" +version = "0.1.0" +dependencies = [ + "ansi_term", + "ctrlc", +] + +[[package]] +name = "nix" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2c5afeb0198ec7be8569d666644b574345aad2e95a53baf3a532da3e0f3fb32" +dependencies = [ + "bitflags", + "cfg-if", + "libc", + "void", +] + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr b/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr index 4f668599be9..f3113e09365 100644 --- a/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr +++ b/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr @@ -1,4 +1,4 @@ -error: multiple versions for dependency `winapi`: 0.2.8, 0.3.8 +error: multiple versions for dependency `winapi`: 0.2.8, 0.3.9 | = note: `-D clippy::multiple-crate-versions` implied by `-D warnings` 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 53970af4107..6fbba01416a 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`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `third-party` at line 5 column 1 +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`, `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`, `third-party` at line 5 column 1 error: aborting due to previous error diff --git a/tests/ui/attrs.rs b/tests/ui/attrs.rs index 91b65a43be7..908d063729f 100644 --- a/tests/ui/attrs.rs +++ b/tests/ui/attrs.rs @@ -1,5 +1,11 @@ #![warn(clippy::inline_always, clippy::deprecated_semver)] #![allow(clippy::assertions_on_constants)] +// Test that the whole restriction group is not enabled +#![warn(clippy::restriction)] +#![deny(clippy::restriction)] +#![forbid(clippy::restriction)] +#![allow(clippy::missing_docs_in_private_items, clippy::panic, clippy::unreachable)] + #[inline(always)] fn test_attr_lint() { assert!(true) diff --git a/tests/ui/attrs.stderr b/tests/ui/attrs.stderr index 39ddf6f226d..ef4b89eaa6d 100644 --- a/tests/ui/attrs.stderr +++ b/tests/ui/attrs.stderr @@ -1,5 +1,5 @@ error: you have declared `#[inline(always)]` on `test_attr_lint`. This is usually a bad idea - --> $DIR/attrs.rs:3:1 + --> $DIR/attrs.rs:9:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[inline(always)] = note: `-D clippy::inline-always` implied by `-D warnings` error: the since field must contain a semver-compliant version - --> $DIR/attrs.rs:23:14 + --> $DIR/attrs.rs:29:14 | LL | #[deprecated(since = "forever")] | ^^^^^^^^^^^^^^^^^ @@ -15,10 +15,35 @@ LL | #[deprecated(since = "forever")] = note: `-D clippy::deprecated-semver` implied by `-D warnings` error: the since field must contain a semver-compliant version - --> $DIR/attrs.rs:26:14 + --> $DIR/attrs.rs:32:14 | LL | #[deprecated(since = "1")] | ^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: restriction lints are not meant to be all enabled + --> $DIR/attrs.rs:4:9 + | +LL | #![warn(clippy::restriction)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings` + = help: try enabling only the lints you really need + +error: restriction lints are not meant to be all enabled + --> $DIR/attrs.rs:5:9 + | +LL | #![deny(clippy::restriction)] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: try enabling only the lints you really need + +error: restriction lints are not meant to be all enabled + --> $DIR/attrs.rs:6:11 + | +LL | #![forbid(clippy::restriction)] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: try enabling only the lints you really need + +error: aborting due to 6 previous errors 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/cmp_owned/asymmetric_partial_eq.fixed b/tests/ui/cmp_owned/asymmetric_partial_eq.fixed new file mode 100644 index 00000000000..3305ac9bf8b --- /dev/null +++ b/tests/ui/cmp_owned/asymmetric_partial_eq.fixed @@ -0,0 +1,93 @@ +// run-rustfix +#![allow(unused, clippy::redundant_clone)] // See #5700 + +// Define the types in each module to avoid trait impls leaking between modules. +macro_rules! impl_types { + () => { + #[derive(PartialEq)] + pub struct Owned; + + pub struct Borrowed; + + impl ToOwned for Borrowed { + type Owned = Owned; + fn to_owned(&self) -> Owned { + Owned {} + } + } + + impl std::borrow::Borrow for Owned { + fn borrow(&self) -> &Borrowed { + static VALUE: Borrowed = Borrowed {}; + &VALUE + } + } + }; +} + +// Only Borrowed == Owned is implemented +mod borrowed_eq_owned { + impl_types!(); + + impl PartialEq for Borrowed { + fn eq(&self, _: &Owned) -> bool { + true + } + } + + pub fn compare() { + let owned = Owned {}; + let borrowed = Borrowed {}; + + if borrowed == owned {} + if borrowed == owned {} + } +} + +// Only Owned == Borrowed is implemented +mod owned_eq_borrowed { + impl_types!(); + + impl PartialEq for Owned { + fn eq(&self, _: &Borrowed) -> bool { + true + } + } + + fn compare() { + let owned = Owned {}; + let borrowed = Borrowed {}; + + if owned == borrowed {} + if owned == borrowed {} + } +} + +mod issue_4874 { + impl_types!(); + + // NOTE: PartialEq for T can't be implemented due to the orphan rules + impl PartialEq for Borrowed + where + T: AsRef + ?Sized, + { + fn eq(&self, _: &T) -> bool { + true + } + } + + impl std::fmt::Display for Borrowed { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "borrowed") + } + } + + fn compare() { + let borrowed = Borrowed {}; + + if borrowed == "Hi" {} + if borrowed == "Hi" {} + } +} + +fn main() {} diff --git a/tests/ui/cmp_owned/asymmetric_partial_eq.rs b/tests/ui/cmp_owned/asymmetric_partial_eq.rs new file mode 100644 index 00000000000..88bc2f51dd6 --- /dev/null +++ b/tests/ui/cmp_owned/asymmetric_partial_eq.rs @@ -0,0 +1,93 @@ +// run-rustfix +#![allow(unused, clippy::redundant_clone)] // See #5700 + +// Define the types in each module to avoid trait impls leaking between modules. +macro_rules! impl_types { + () => { + #[derive(PartialEq)] + pub struct Owned; + + pub struct Borrowed; + + impl ToOwned for Borrowed { + type Owned = Owned; + fn to_owned(&self) -> Owned { + Owned {} + } + } + + impl std::borrow::Borrow for Owned { + fn borrow(&self) -> &Borrowed { + static VALUE: Borrowed = Borrowed {}; + &VALUE + } + } + }; +} + +// Only Borrowed == Owned is implemented +mod borrowed_eq_owned { + impl_types!(); + + impl PartialEq for Borrowed { + fn eq(&self, _: &Owned) -> bool { + true + } + } + + pub fn compare() { + let owned = Owned {}; + let borrowed = Borrowed {}; + + if borrowed.to_owned() == owned {} + if owned == borrowed.to_owned() {} + } +} + +// Only Owned == Borrowed is implemented +mod owned_eq_borrowed { + impl_types!(); + + impl PartialEq for Owned { + fn eq(&self, _: &Borrowed) -> bool { + true + } + } + + fn compare() { + let owned = Owned {}; + let borrowed = Borrowed {}; + + if owned == borrowed.to_owned() {} + if borrowed.to_owned() == owned {} + } +} + +mod issue_4874 { + impl_types!(); + + // NOTE: PartialEq for T can't be implemented due to the orphan rules + impl PartialEq for Borrowed + where + T: AsRef + ?Sized, + { + fn eq(&self, _: &T) -> bool { + true + } + } + + impl std::fmt::Display for Borrowed { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "borrowed") + } + } + + fn compare() { + let borrowed = Borrowed {}; + + if "Hi" == borrowed.to_string() {} + if borrowed.to_string() == "Hi" {} + } +} + +fn main() {} diff --git a/tests/ui/cmp_owned/asymmetric_partial_eq.stderr b/tests/ui/cmp_owned/asymmetric_partial_eq.stderr new file mode 100644 index 00000000000..43bf8851fc6 --- /dev/null +++ b/tests/ui/cmp_owned/asymmetric_partial_eq.stderr @@ -0,0 +1,46 @@ +error: this creates an owned instance just for comparison + --> $DIR/asymmetric_partial_eq.rs:42:12 + | +LL | if borrowed.to_owned() == owned {} + | ^^^^^^^^^^^^^^^^^^^ help: try: `borrowed` + | + = note: `-D clippy::cmp-owned` implied by `-D warnings` + +error: this creates an owned instance just for comparison + --> $DIR/asymmetric_partial_eq.rs:43:21 + | +LL | if owned == borrowed.to_owned() {} + | ---------^^^^^^^^^^^^^^^^^^^ + | | + | help: try: `borrowed == owned` + +error: this creates an owned instance just for comparison + --> $DIR/asymmetric_partial_eq.rs:61:21 + | +LL | if owned == borrowed.to_owned() {} + | ^^^^^^^^^^^^^^^^^^^ help: try: `borrowed` + +error: this creates an owned instance just for comparison + --> $DIR/asymmetric_partial_eq.rs:62:12 + | +LL | if borrowed.to_owned() == owned {} + | ^^^^^^^^^^^^^^^^^^^--------- + | | + | help: try: `owned == borrowed` + +error: this creates an owned instance just for comparison + --> $DIR/asymmetric_partial_eq.rs:88:20 + | +LL | if "Hi" == borrowed.to_string() {} + | --------^^^^^^^^^^^^^^^^^^^^ + | | + | help: try: `borrowed == "Hi"` + +error: this creates an owned instance just for comparison + --> $DIR/asymmetric_partial_eq.rs:89:12 + | +LL | if borrowed.to_string() == "Hi" {} + | ^^^^^^^^^^^^^^^^^^^^ help: try: `borrowed` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/collapsible_else_if.stderr b/tests/ui/collapsible_else_if.stderr index 28048999e8e..3d1c458879e 100644 --- a/tests/ui/collapsible_else_if.stderr +++ b/tests/ui/collapsible_else_if.stderr @@ -10,7 +10,7 @@ LL | | } | |_____^ | = note: `-D clippy::collapsible-if` implied by `-D warnings` -help: try +help: collapse nested if block | LL | } else if y == "world" { LL | println!("world!") @@ -28,7 +28,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | } else if let Some(42) = Some(42) { LL | println!("world!") @@ -48,7 +48,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | } else if y == "world" { LL | println!("world") @@ -71,7 +71,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | } else if let Some(42) = Some(42) { LL | println!("world") @@ -94,7 +94,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | } else if let Some(42) = Some(42) { LL | println!("world") @@ -117,7 +117,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | } else if x == "hello" { LL | println!("world") @@ -140,7 +140,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | } else if let Some(42) = Some(42) { LL | println!("world") diff --git a/tests/ui/collapsible_if.stderr b/tests/ui/collapsible_if.stderr index 6440ff41be8..f56dd65b9dd 100644 --- a/tests/ui/collapsible_if.stderr +++ b/tests/ui/collapsible_if.stderr @@ -9,7 +9,7 @@ LL | | } | |_____^ | = note: `-D clippy::collapsible-if` implied by `-D warnings` -help: try +help: collapse nested if block | LL | if x == "hello" && y == "world" { LL | println!("Hello world!"); @@ -26,7 +26,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | if (x == "hello" || x == "world") && (y == "world" || y == "hello") { LL | println!("Hello world!"); @@ -43,7 +43,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | if x == "hello" && x == "world" && (y == "world" || y == "hello") { LL | println!("Hello world!"); @@ -60,7 +60,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | if (x == "hello" || x == "world") && y == "world" && y == "hello" { LL | println!("Hello world!"); @@ -77,7 +77,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | if x == "hello" && x == "world" && y == "world" && y == "hello" { LL | println!("Hello world!"); @@ -94,7 +94,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | if 42 == 1337 && 'a' != 'A' { LL | println!("world!") @@ -111,7 +111,7 @@ LL | | } LL | | } | |_____^ | -help: try +help: collapse nested if block | LL | if x == "hello" && y == "world" { // Collapsible LL | println!("Hello world!"); diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs index 188a641aa1a..3eefb232780 100644 --- a/tests/ui/deprecated.rs +++ b/tests/ui/deprecated.rs @@ -7,5 +7,6 @@ #[warn(clippy::invalid_ref)] #[warn(clippy::into_iter_on_array)] #[warn(clippy::unused_label)] +#[warn(clippy::regex_macro)] fn main() {} diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr index a4efe3d15a9..a80e2bf31fe 100644 --- a/tests/ui/deprecated.stderr +++ b/tests/ui/deprecated.stderr @@ -54,11 +54,17 @@ error: lint `clippy::unused_label` has been removed: `this lint has been uplifte LL | #[warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ +error: lint `clippy::regex_macro` has been removed: `the regex! macro has been removed from the regex crate in 2018` + --> $DIR/deprecated.rs:10:8 + | +LL | #[warn(clippy::regex_macro)] + | ^^^^^^^^^^^^^^^^^^^ + error: lint `clippy::str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon` --> $DIR/deprecated.rs:1:8 | LL | #[warn(clippy::str_to_string)] | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors diff --git a/tests/ui/find_map.rs b/tests/ui/find_map.rs index c28cca144ca..88d3b0e7490 100644 --- a/tests/ui/find_map.rs +++ b/tests/ui/find_map.rs @@ -19,6 +19,7 @@ fn main() { let _: Option = a.iter().find(|s| s.parse::().is_ok()).map(|s| s.parse().unwrap()); + #[allow(clippy::match_like_matches_macro)] let _: Option = desserts_of_the_week .iter() .find(|dessert| match *dessert { diff --git a/tests/ui/find_map.stderr b/tests/ui/find_map.stderr index 92f40fe6f1f..f279850fef8 100644 --- a/tests/ui/find_map.stderr +++ b/tests/ui/find_map.stderr @@ -8,7 +8,7 @@ LL | let _: Option = a.iter().find(|s| s.parse::().is_ok()).map(|s = help: this is more succinctly expressed by calling `.find_map(..)` instead error: called `find(p).map(q)` on an `Iterator` - --> $DIR/find_map.rs:22:29 + --> $DIR/find_map.rs:23:29 | LL | let _: Option = desserts_of_the_week | _____________________________^ diff --git a/tests/ui/floating_point_hypot.fixed b/tests/ui/floating_point_hypot.fixed new file mode 100644 index 00000000000..bbe411b3f48 --- /dev/null +++ b/tests/ui/floating_point_hypot.fixed @@ -0,0 +1,14 @@ +// run-rustfix +#![warn(clippy::imprecise_flops)] + +fn main() { + let x = 3f32; + let y = 4f32; + let _ = x.hypot(y); + let _ = (x + 1f32).hypot(y); + let _ = x.hypot(y); + // Cases where the lint shouldn't be applied + // TODO: linting this adds some complexity, but could be done + let _ = x.mul_add(x, y * y).sqrt(); + let _ = (x * 4f32 + y * y).sqrt(); +} diff --git a/tests/ui/floating_point_hypot.rs b/tests/ui/floating_point_hypot.rs new file mode 100644 index 00000000000..586fd170ea1 --- /dev/null +++ b/tests/ui/floating_point_hypot.rs @@ -0,0 +1,14 @@ +// run-rustfix +#![warn(clippy::imprecise_flops)] + +fn main() { + let x = 3f32; + let y = 4f32; + let _ = (x * x + y * y).sqrt(); + let _ = ((x + 1f32) * (x + 1f32) + y * y).sqrt(); + let _ = (x.powi(2) + y.powi(2)).sqrt(); + // Cases where the lint shouldn't be applied + // TODO: linting this adds some complexity, but could be done + let _ = x.mul_add(x, y * y).sqrt(); + let _ = (x * 4f32 + y * y).sqrt(); +} diff --git a/tests/ui/floating_point_hypot.stderr b/tests/ui/floating_point_hypot.stderr new file mode 100644 index 00000000000..42069d9ee9e --- /dev/null +++ b/tests/ui/floating_point_hypot.stderr @@ -0,0 +1,22 @@ +error: hypotenuse can be computed more accurately + --> $DIR/floating_point_hypot.rs:7:13 + | +LL | let _ = (x * x + y * y).sqrt(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.hypot(y)` + | + = note: `-D clippy::imprecise-flops` implied by `-D warnings` + +error: hypotenuse can be computed more accurately + --> $DIR/floating_point_hypot.rs:8:13 + | +LL | let _ = ((x + 1f32) * (x + 1f32) + y * y).sqrt(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 1f32).hypot(y)` + +error: hypotenuse can be computed more accurately + --> $DIR/floating_point_hypot.rs:9:13 + | +LL | let _ = (x.powi(2) + y.powi(2)).sqrt(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.hypot(y)` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/floating_point_log.fixed b/tests/ui/floating_point_log.fixed index 42c5e5d2bae..7dc7ee94aff 100644 --- a/tests/ui/floating_point_log.fixed +++ b/tests/ui/floating_point_log.fixed @@ -25,11 +25,11 @@ fn check_ln1p() { let _ = 2.0f32.ln_1p(); let _ = x.ln_1p(); let _ = (x / 2.0).ln_1p(); - let _ = x.powi(2).ln_1p(); - let _ = (x.powi(2) / 2.0).ln_1p(); + let _ = x.powi(3).ln_1p(); + let _ = (x.powi(3) / 2.0).ln_1p(); let _ = ((std::f32::consts::E - 1.0)).ln_1p(); let _ = x.ln_1p(); - let _ = x.powi(2).ln_1p(); + let _ = x.powi(3).ln_1p(); let _ = (x + 2.0).ln_1p(); let _ = (x / 2.0).ln_1p(); // Cases where the lint shouldn't be applied @@ -43,9 +43,9 @@ fn check_ln1p() { let _ = 2.0f64.ln_1p(); let _ = x.ln_1p(); let _ = (x / 2.0).ln_1p(); - let _ = x.powi(2).ln_1p(); + let _ = x.powi(3).ln_1p(); let _ = x.ln_1p(); - let _ = x.powi(2).ln_1p(); + let _ = x.powi(3).ln_1p(); let _ = (x + 2.0).ln_1p(); let _ = (x / 2.0).ln_1p(); // Cases where the lint shouldn't be applied diff --git a/tests/ui/floating_point_log.rs b/tests/ui/floating_point_log.rs index 8be0d9ad56f..01181484e7d 100644 --- a/tests/ui/floating_point_log.rs +++ b/tests/ui/floating_point_log.rs @@ -25,11 +25,11 @@ fn check_ln1p() { let _ = (1f32 + 2.0).ln(); let _ = (1.0 + x).ln(); let _ = (1.0 + x / 2.0).ln(); - let _ = (1.0 + x.powi(2)).ln(); - let _ = (1.0 + x.powi(2) / 2.0).ln(); + let _ = (1.0 + x.powi(3)).ln(); + let _ = (1.0 + x.powi(3) / 2.0).ln(); let _ = (1.0 + (std::f32::consts::E - 1.0)).ln(); let _ = (x + 1.0).ln(); - let _ = (x.powi(2) + 1.0).ln(); + let _ = (x.powi(3) + 1.0).ln(); let _ = (x + 2.0 + 1.0).ln(); let _ = (x / 2.0 + 1.0).ln(); // Cases where the lint shouldn't be applied @@ -43,9 +43,9 @@ fn check_ln1p() { let _ = (1f64 + 2.0).ln(); let _ = (1.0 + x).ln(); let _ = (1.0 + x / 2.0).ln(); - let _ = (1.0 + x.powi(2)).ln(); + let _ = (1.0 + x.powi(3)).ln(); let _ = (x + 1.0).ln(); - let _ = (x.powi(2) + 1.0).ln(); + let _ = (x.powi(3) + 1.0).ln(); let _ = (x + 2.0 + 1.0).ln(); let _ = (x / 2.0 + 1.0).ln(); // Cases where the lint shouldn't be applied diff --git a/tests/ui/floating_point_log.stderr b/tests/ui/floating_point_log.stderr index 943fbdb0b83..900dc2b7933 100644 --- a/tests/ui/floating_point_log.stderr +++ b/tests/ui/floating_point_log.stderr @@ -77,14 +77,14 @@ LL | let _ = (1.0 + x / 2.0).ln(); error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:28:13 | -LL | let _ = (1.0 + x.powi(2)).ln(); - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` +LL | let _ = (1.0 + x.powi(3)).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:29:13 | -LL | let _ = (1.0 + x.powi(2) / 2.0).ln(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(2) / 2.0).ln_1p()` +LL | let _ = (1.0 + x.powi(3) / 2.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(3) / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:30:13 @@ -101,8 +101,8 @@ LL | let _ = (x + 1.0).ln(); error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:32:13 | -LL | let _ = (x.powi(2) + 1.0).ln(); - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` +LL | let _ = (x.powi(3) + 1.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:33:13 @@ -143,8 +143,8 @@ LL | let _ = (1.0 + x / 2.0).ln(); error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:46:13 | -LL | let _ = (1.0 + x.powi(2)).ln(); - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` +LL | let _ = (1.0 + x.powi(3)).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:47:13 @@ -155,8 +155,8 @@ LL | let _ = (x + 1.0).ln(); error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:48:13 | -LL | let _ = (x.powi(2) + 1.0).ln(); - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()` +LL | let _ = (x.powi(3) + 1.0).ln(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()` error: ln(1 + x) can be computed more accurately --> $DIR/floating_point_log.rs:49:13 diff --git a/tests/ui/floating_point_logbase.fixed b/tests/ui/floating_point_logbase.fixed new file mode 100644 index 00000000000..13962a272d4 --- /dev/null +++ b/tests/ui/floating_point_logbase.fixed @@ -0,0 +1,16 @@ +// run-rustfix +#![warn(clippy::suboptimal_flops)] + +fn main() { + let x = 3f32; + let y = 5f32; + let _ = x.log(y); + let _ = x.log(y); + let _ = x.log(y); + let _ = x.log(y); + // Cases where the lint shouldn't be applied + let _ = x.ln() / y.powf(3.2); + let _ = x.powf(3.2) / y.powf(3.2); + let _ = x.powf(3.2) / y.ln(); + let _ = x.log(5f32) / y.log(7f32); +} diff --git a/tests/ui/floating_point_logbase.rs b/tests/ui/floating_point_logbase.rs new file mode 100644 index 00000000000..26bc20d5370 --- /dev/null +++ b/tests/ui/floating_point_logbase.rs @@ -0,0 +1,16 @@ +// run-rustfix +#![warn(clippy::suboptimal_flops)] + +fn main() { + let x = 3f32; + let y = 5f32; + let _ = x.ln() / y.ln(); + let _ = x.log2() / y.log2(); + let _ = x.log10() / y.log10(); + let _ = x.log(5f32) / y.log(5f32); + // Cases where the lint shouldn't be applied + let _ = x.ln() / y.powf(3.2); + let _ = x.powf(3.2) / y.powf(3.2); + let _ = x.powf(3.2) / y.ln(); + let _ = x.log(5f32) / y.log(7f32); +} diff --git a/tests/ui/floating_point_logbase.stderr b/tests/ui/floating_point_logbase.stderr new file mode 100644 index 00000000000..78354c2f62d --- /dev/null +++ b/tests/ui/floating_point_logbase.stderr @@ -0,0 +1,28 @@ +error: log base can be expressed more clearly + --> $DIR/floating_point_logbase.rs:7:13 + | +LL | let _ = x.ln() / y.ln(); + | ^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` + | + = note: `-D clippy::suboptimal-flops` implied by `-D warnings` + +error: log base can be expressed more clearly + --> $DIR/floating_point_logbase.rs:8:13 + | +LL | let _ = x.log2() / y.log2(); + | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` + +error: log base can be expressed more clearly + --> $DIR/floating_point_logbase.rs:9:13 + | +LL | let _ = x.log10() / y.log10(); + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` + +error: log base can be expressed more clearly + --> $DIR/floating_point_logbase.rs:10:13 + | +LL | let _ = x.log(5f32) / y.log(5f32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/floating_point_mul_add.fixed b/tests/ui/floating_point_mul_add.fixed index e343c37740d..911700bab00 100644 --- a/tests/ui/floating_point_mul_add.fixed +++ b/tests/ui/floating_point_mul_add.fixed @@ -18,4 +18,9 @@ fn main() { let _ = a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c)) + c; let _ = 1234.567_f64.mul_add(45.67834_f64, 0.0004_f64); + + let _ = a.mul_add(a, b).sqrt(); + + // Cases where the lint shouldn't be applied + let _ = (a * a + b * b).sqrt(); } diff --git a/tests/ui/floating_point_mul_add.rs b/tests/ui/floating_point_mul_add.rs index 810f929c856..d202385fc8a 100644 --- a/tests/ui/floating_point_mul_add.rs +++ b/tests/ui/floating_point_mul_add.rs @@ -18,4 +18,9 @@ fn main() { let _ = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c; let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; + + let _ = (a * a + b).sqrt(); + + // Cases where the lint shouldn't be applied + let _ = (a * a + b * b).sqrt(); } diff --git a/tests/ui/floating_point_mul_add.stderr b/tests/ui/floating_point_mul_add.stderr index 2dfbf562d15..ac8d0c0cae0 100644 --- a/tests/ui/floating_point_mul_add.stderr +++ b/tests/ui/floating_point_mul_add.stderr @@ -54,5 +54,11 @@ error: multiply and add expressions can be calculated more efficiently and accur LL | let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1234.567_f64.mul_add(45.67834_f64, 0.0004_f64)` -error: aborting due to 9 previous errors +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_mul_add.rs:22:13 + | +LL | let _ = (a * a + b).sqrt(); + | ^^^^^^^^^^^ help: consider using: `a.mul_add(a, b)` + +error: aborting due to 10 previous errors diff --git a/tests/ui/floating_point_powf.fixed b/tests/ui/floating_point_powf.fixed index 78a9d44829b..b0641a100cd 100644 --- a/tests/ui/floating_point_powf.fixed +++ b/tests/ui/floating_point_powf.fixed @@ -11,7 +11,7 @@ fn main() { let _ = (-3.1f32).exp(); let _ = x.sqrt(); let _ = x.cbrt(); - let _ = x.powi(2); + let _ = x.powi(3); let _ = x.powi(-2); let _ = x.powi(16_777_215); let _ = x.powi(-16_777_215); @@ -30,7 +30,7 @@ fn main() { let _ = (-3.1f64).exp(); let _ = x.sqrt(); let _ = x.cbrt(); - let _ = x.powi(2); + let _ = x.powi(3); let _ = x.powi(-2); let _ = x.powi(-2_147_483_648); let _ = x.powi(2_147_483_647); diff --git a/tests/ui/floating_point_powf.rs b/tests/ui/floating_point_powf.rs index dbc1cac5cb4..a0a2c973900 100644 --- a/tests/ui/floating_point_powf.rs +++ b/tests/ui/floating_point_powf.rs @@ -11,7 +11,7 @@ fn main() { let _ = std::f32::consts::E.powf(-3.1); let _ = x.powf(1.0 / 2.0); let _ = x.powf(1.0 / 3.0); - let _ = x.powf(2.0); + let _ = x.powf(3.0); let _ = x.powf(-2.0); let _ = x.powf(16_777_215.0); let _ = x.powf(-16_777_215.0); @@ -30,7 +30,7 @@ fn main() { let _ = std::f64::consts::E.powf(-3.1); let _ = x.powf(1.0 / 2.0); let _ = x.powf(1.0 / 3.0); - let _ = x.powf(2.0); + let _ = x.powf(3.0); let _ = x.powf(-2.0); let _ = x.powf(-2_147_483_648.0); let _ = x.powf(2_147_483_647.0); diff --git a/tests/ui/floating_point_powf.stderr b/tests/ui/floating_point_powf.stderr index ad5163f0079..2422eb911e9 100644 --- a/tests/ui/floating_point_powf.stderr +++ b/tests/ui/floating_point_powf.stderr @@ -53,8 +53,8 @@ LL | let _ = x.powf(1.0 / 3.0); error: exponentiation with integer powers can be computed more efficiently --> $DIR/floating_point_powf.rs:14:13 | -LL | let _ = x.powf(2.0); - | ^^^^^^^^^^^ help: consider using: `x.powi(2)` +LL | let _ = x.powf(3.0); + | ^^^^^^^^^^^ help: consider using: `x.powi(3)` error: exponentiation with integer powers can be computed more efficiently --> $DIR/floating_point_powf.rs:15:13 @@ -125,8 +125,8 @@ LL | let _ = x.powf(1.0 / 3.0); error: exponentiation with integer powers can be computed more efficiently --> $DIR/floating_point_powf.rs:33:13 | -LL | let _ = x.powf(2.0); - | ^^^^^^^^^^^ help: consider using: `x.powi(2)` +LL | let _ = x.powf(3.0); + | ^^^^^^^^^^^ help: consider using: `x.powi(3)` error: exponentiation with integer powers can be computed more efficiently --> $DIR/floating_point_powf.rs:34:13 diff --git a/tests/ui/floating_point_powi.fixed b/tests/ui/floating_point_powi.fixed new file mode 100644 index 00000000000..56762400593 --- /dev/null +++ b/tests/ui/floating_point_powi.fixed @@ -0,0 +1,19 @@ +// run-rustfix +#![warn(clippy::suboptimal_flops)] + +fn main() { + let one = 1; + let x = 3f32; + let _ = x * x; + let _ = x * x; + + let y = 4f32; + let _ = x.mul_add(x, y); + let _ = y.mul_add(y, x); + let _ = x.mul_add(x, y).sqrt(); + let _ = y.mul_add(y, x).sqrt(); + // Cases where the lint shouldn't be applied + let _ = x.powi(3); + let _ = x.powi(one + 1); + let _ = (x.powi(2) + y.powi(2)).sqrt(); +} diff --git a/tests/ui/floating_point_powi.rs b/tests/ui/floating_point_powi.rs new file mode 100644 index 00000000000..1f800e4628d --- /dev/null +++ b/tests/ui/floating_point_powi.rs @@ -0,0 +1,19 @@ +// run-rustfix +#![warn(clippy::suboptimal_flops)] + +fn main() { + let one = 1; + let x = 3f32; + let _ = x.powi(2); + let _ = x.powi(1 + 1); + + let y = 4f32; + let _ = x.powi(2) + y; + let _ = x + y.powi(2); + let _ = (x.powi(2) + y).sqrt(); + let _ = (x + y.powi(2)).sqrt(); + // Cases where the lint shouldn't be applied + let _ = x.powi(3); + let _ = x.powi(one + 1); + let _ = (x.powi(2) + y.powi(2)).sqrt(); +} diff --git a/tests/ui/floating_point_powi.stderr b/tests/ui/floating_point_powi.stderr new file mode 100644 index 00000000000..d5a5f1bcca1 --- /dev/null +++ b/tests/ui/floating_point_powi.stderr @@ -0,0 +1,40 @@ +error: square can be computed more efficiently + --> $DIR/floating_point_powi.rs:7:13 + | +LL | let _ = x.powi(2); + | ^^^^^^^^^ help: consider using: `x * x` + | + = note: `-D clippy::suboptimal-flops` implied by `-D warnings` + +error: square can be computed more efficiently + --> $DIR/floating_point_powi.rs:8:13 + | +LL | let _ = x.powi(1 + 1); + | ^^^^^^^^^^^^^ help: consider using: `x * x` + +error: square can be computed more efficiently + --> $DIR/floating_point_powi.rs:11:13 + | +LL | let _ = x.powi(2) + y; + | ^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)` + +error: square can be computed more efficiently + --> $DIR/floating_point_powi.rs:12:13 + | +LL | let _ = x + y.powi(2); + | ^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)` + +error: square can be computed more efficiently + --> $DIR/floating_point_powi.rs:13:13 + | +LL | let _ = (x.powi(2) + y).sqrt(); + | ^^^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)` + +error: square can be computed more efficiently + --> $DIR/floating_point_powi.rs:14:13 + | +LL | let _ = (x + y.powi(2)).sqrt(); + | ^^^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/floating_point_rad.fixed b/tests/ui/floating_point_rad.fixed new file mode 100644 index 00000000000..92480c5db8b --- /dev/null +++ b/tests/ui/floating_point_rad.fixed @@ -0,0 +1,13 @@ +// run-rustfix +#![warn(clippy::suboptimal_flops)] + +fn main() { + let x = 3f32; + let _ = x.to_degrees(); + let _ = x.to_radians(); + // Cases where the lint shouldn't be applied + let _ = x * 90f32 / std::f32::consts::PI; + let _ = x * std::f32::consts::PI / 90f32; + let _ = x * 180f32 / std::f32::consts::E; + let _ = x * std::f32::consts::E / 180f32; +} diff --git a/tests/ui/floating_point_rad.rs b/tests/ui/floating_point_rad.rs new file mode 100644 index 00000000000..062e7c3fdc1 --- /dev/null +++ b/tests/ui/floating_point_rad.rs @@ -0,0 +1,13 @@ +// run-rustfix +#![warn(clippy::suboptimal_flops)] + +fn main() { + let x = 3f32; + let _ = x * 180f32 / std::f32::consts::PI; + let _ = x * std::f32::consts::PI / 180f32; + // Cases where the lint shouldn't be applied + let _ = x * 90f32 / std::f32::consts::PI; + let _ = x * std::f32::consts::PI / 90f32; + let _ = x * 180f32 / std::f32::consts::E; + let _ = x * std::f32::consts::E / 180f32; +} diff --git a/tests/ui/floating_point_rad.stderr b/tests/ui/floating_point_rad.stderr new file mode 100644 index 00000000000..a6ffdca64ee --- /dev/null +++ b/tests/ui/floating_point_rad.stderr @@ -0,0 +1,16 @@ +error: conversion to degrees can be done more accurately + --> $DIR/floating_point_rad.rs:6:13 + | +LL | let _ = x * 180f32 / std::f32::consts::PI; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_degrees()` + | + = note: `-D clippy::suboptimal-flops` implied by `-D warnings` + +error: conversion to radians can be done more accurately + --> $DIR/floating_point_rad.rs:7:13 + | +LL | let _ = x * std::f32::consts::PI / 180f32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_radians()` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/map_flatten.fixed b/tests/ui/map_flatten.fixed index 7ac368878ab..4171d80f48a 100644 --- a/tests/ui/map_flatten.fixed +++ b/tests/ui/map_flatten.fixed @@ -2,6 +2,7 @@ #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::missing_docs_in_private_items)] +#![allow(clippy::map_identity)] fn main() { let _: Vec<_> = vec![5_i8; 6].into_iter().flat_map(|x| 0..x).collect(); diff --git a/tests/ui/map_flatten.rs b/tests/ui/map_flatten.rs index a608601039c..16a0fd090ad 100644 --- a/tests/ui/map_flatten.rs +++ b/tests/ui/map_flatten.rs @@ -2,6 +2,7 @@ #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::missing_docs_in_private_items)] +#![allow(clippy::map_identity)] fn main() { let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); diff --git a/tests/ui/map_flatten.stderr b/tests/ui/map_flatten.stderr index 3cf2abd5b6d..00bc41c15e9 100644 --- a/tests/ui/map_flatten.stderr +++ b/tests/ui/map_flatten.stderr @@ -1,5 +1,5 @@ error: called `map(..).flatten()` on an `Iterator`. This is more succinctly expressed by calling `.flat_map(..)` - --> $DIR/map_flatten.rs:7:21 + --> $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)` @@ -7,7 +7,7 @@ LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().colle = note: `-D clippy::map-flatten` implied by `-D warnings` error: called `map(..).flatten()` on an `Option`. This is more succinctly expressed by calling `.and_then(..)` - --> $DIR/map_flatten.rs:8:24 + --> $DIR/map_flatten.rs:9:24 | LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `(Some(Some(1))).and_then(|x| x)` diff --git a/tests/ui/map_identity.fixed b/tests/ui/map_identity.fixed new file mode 100644 index 00000000000..4a1452b25f3 --- /dev/null +++ b/tests/ui/map_identity.fixed @@ -0,0 +1,23 @@ +// run-rustfix +#![warn(clippy::map_identity)] +#![allow(clippy::needless_return)] + +fn main() { + let x: [u16; 3] = [1, 2, 3]; + // should lint + let _: Vec<_> = x.iter().map(not_identity).collect(); + let _: Vec<_> = x.iter().collect(); + let _: Option = Some(3); + let _: Result = Ok(-3); + // should not lint + let _: Vec<_> = x.iter().map(|x| 2 * x).collect(); + let _: Vec<_> = x.iter().map(not_identity).map(|x| return x - 4).collect(); + let _: Option = None.map(|x: u8| x - 1); + let _: Result = Err(2.3).map(|x: i8| { + return x + 3; + }); +} + +fn not_identity(x: &u16) -> u16 { + *x +} diff --git a/tests/ui/map_identity.rs b/tests/ui/map_identity.rs new file mode 100644 index 00000000000..65c7e6e1ea5 --- /dev/null +++ b/tests/ui/map_identity.rs @@ -0,0 +1,25 @@ +// run-rustfix +#![warn(clippy::map_identity)] +#![allow(clippy::needless_return)] + +fn main() { + let x: [u16; 3] = [1, 2, 3]; + // should lint + let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect(); + let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect(); + let _: Option = Some(3).map(|x| x); + let _: Result = Ok(-3).map(|x| { + return x; + }); + // should not lint + let _: Vec<_> = x.iter().map(|x| 2 * x).collect(); + let _: Vec<_> = x.iter().map(not_identity).map(|x| return x - 4).collect(); + let _: Option = None.map(|x: u8| x - 1); + let _: Result = Err(2.3).map(|x: i8| { + return x + 3; + }); +} + +fn not_identity(x: &u16) -> u16 { + *x +} diff --git a/tests/ui/map_identity.stderr b/tests/ui/map_identity.stderr new file mode 100644 index 00000000000..e4a0320cbda --- /dev/null +++ b/tests/ui/map_identity.stderr @@ -0,0 +1,37 @@ +error: unnecessary map of the identity function + --> $DIR/map_identity.rs:8:47 + | +LL | let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect(); + | ^^^^^^^^^^^^^^^^^^ help: remove the call to `map` + | + = note: `-D clippy::map-identity` implied by `-D warnings` + +error: unnecessary map of the identity function + --> $DIR/map_identity.rs:9:57 + | +LL | let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect(); + | ^^^^^^^^^^^ help: remove the call to `map` + +error: unnecessary map of the identity function + --> $DIR/map_identity.rs:9:29 + | +LL | let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` + +error: unnecessary map of the identity function + --> $DIR/map_identity.rs:10:32 + | +LL | let _: Option = Some(3).map(|x| x); + | ^^^^^^^^^^^ help: remove the call to `map` + +error: unnecessary map of the identity function + --> $DIR/map_identity.rs:11:36 + | +LL | let _: Result = Ok(-3).map(|x| { + | ____________________________________^ +LL | | return x; +LL | | }); + | |______^ help: remove the call to `map` + +error: aborting due to 5 previous errors + diff --git a/tests/ui/match_expr_like_matches_macro.fixed b/tests/ui/match_expr_like_matches_macro.fixed new file mode 100644 index 00000000000..f3e19092480 --- /dev/null +++ b/tests/ui/match_expr_like_matches_macro.fixed @@ -0,0 +1,36 @@ +// run-rustfix + +#![warn(clippy::match_like_matches_macro)] +#![allow(unreachable_patterns)] + +fn main() { + let x = Some(5); + + // Lint + let _y = matches!(x, Some(0)); + + // Lint + let _w = matches!(x, Some(_)); + + // Turn into is_none + let _z = x.is_none(); + + // Lint + let _zz = !matches!(x, Some(r) if r == 0); + + // Lint + let _zzz = matches!(x, Some(5)); + + // No lint + let _a = match x { + Some(_) => false, + _ => false, + }; + + // No lint + let _ab = match x { + Some(0) => false, + _ => true, + None => false, + }; +} diff --git a/tests/ui/match_expr_like_matches_macro.rs b/tests/ui/match_expr_like_matches_macro.rs new file mode 100644 index 00000000000..fbae7c18b92 --- /dev/null +++ b/tests/ui/match_expr_like_matches_macro.rs @@ -0,0 +1,48 @@ +// run-rustfix + +#![warn(clippy::match_like_matches_macro)] +#![allow(unreachable_patterns)] + +fn main() { + let x = Some(5); + + // Lint + let _y = match x { + Some(0) => true, + _ => false, + }; + + // Lint + let _w = match x { + Some(_) => true, + _ => false, + }; + + // Turn into is_none + let _z = match x { + Some(_) => false, + None => true, + }; + + // Lint + let _zz = match x { + Some(r) if r == 0 => false, + _ => true, + }; + + // Lint + let _zzz = if let Some(5) = x { true } else { false }; + + // No lint + let _a = match x { + Some(_) => false, + _ => false, + }; + + // No lint + let _ab = match x { + Some(0) => false, + _ => true, + None => false, + }; +} diff --git a/tests/ui/match_expr_like_matches_macro.stderr b/tests/ui/match_expr_like_matches_macro.stderr new file mode 100644 index 00000000000..4668f8565a6 --- /dev/null +++ b/tests/ui/match_expr_like_matches_macro.stderr @@ -0,0 +1,52 @@ +error: match expression looks like `matches!` macro + --> $DIR/match_expr_like_matches_macro.rs:10:14 + | +LL | let _y = match x { + | ______________^ +LL | | Some(0) => true, +LL | | _ => false, +LL | | }; + | |_____^ help: try this: `matches!(x, Some(0))` + | + = note: `-D clippy::match-like-matches-macro` implied by `-D warnings` + +error: match expression looks like `matches!` macro + --> $DIR/match_expr_like_matches_macro.rs:16:14 + | +LL | let _w = match x { + | ______________^ +LL | | Some(_) => true, +LL | | _ => false, +LL | | }; + | |_____^ help: try this: `matches!(x, Some(_))` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/match_expr_like_matches_macro.rs:22:14 + | +LL | let _z = match x { + | ______________^ +LL | | Some(_) => false, +LL | | None => true, +LL | | }; + | |_____^ help: try this: `x.is_none()` + | + = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` + +error: match expression looks like `matches!` macro + --> $DIR/match_expr_like_matches_macro.rs:28:15 + | +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)` + +error: if let .. else expression looks like `matches!` macro + --> $DIR/match_expr_like_matches_macro.rs:34:16 + | +LL | let _zzz = if let Some(5) = x { true } else { false }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `matches!(x, Some(5))` + +error: aborting due to 5 previous errors + diff --git a/tests/ui/neg_cmp_op_on_partial_ord.rs b/tests/ui/neg_cmp_op_on_partial_ord.rs index 0b471195272..2d392c593b3 100644 --- a/tests/ui/neg_cmp_op_on_partial_ord.rs +++ b/tests/ui/neg_cmp_op_on_partial_ord.rs @@ -4,7 +4,7 @@ use std::cmp::Ordering; -#[allow(clippy::unnested_or_patterns)] +#[allow(clippy::unnested_or_patterns, clippy::match_like_matches_macro)] #[warn(clippy::neg_cmp_op_on_partial_ord)] fn main() { let a_value = 1.0; diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed new file mode 100644 index 00000000000..695a460cc4e --- /dev/null +++ b/tests/ui/option_if_let_else.fixed @@ -0,0 +1,74 @@ +// run-rustfix +#![warn(clippy::option_if_let_else)] + +fn bad1(string: Option<&str>) -> (bool, &str) { + string.map_or((false, "hello"), |x| (true, x)) +} + +fn else_if_option(string: Option<&str>) -> Option<(bool, &str)> { + if string.is_none() { + None + } else { string.map_or(Some((false, "")), |x| Some((true, x))) } +} + +fn unop_bad(string: &Option<&str>, mut num: Option) { + let _ = string.map_or(0, |s| s.len()); + let _ = num.as_ref().map_or(&0, |s| s); + let _ = num.as_mut().map_or(&mut 0, |s| { + *s += 1; + s + }); + let _ = num.as_ref().map_or(&0, |s| s); + let _ = num.map_or(0, |mut s| { + s += 1; + s + }); + let _ = num.as_mut().map_or(&mut 0, |s| { + *s += 1; + s + }); +} + +fn longer_body(arg: Option) -> u32 { + arg.map_or(13, |x| { + let y = x * x; + y * y + }) +} + +fn test_map_or_else(arg: Option) { + let _ = arg.map_or_else(|| { + let mut y = 1; + y = (y + 2 / y) / 2; + y = (y + 2 / y) / 2; + y + }, |x| x * x * x * x); +} + +fn negative_tests(arg: Option) -> u32 { + let _ = if let Some(13) = arg { "unlucky" } else { "lucky" }; + for _ in 0..10 { + let _ = if let Some(x) = arg { + x + } else { + continue; + }; + } + let _ = if let Some(x) = arg { + return x; + } else { + 5 + }; + 7 +} + +fn main() { + let optional = Some(5); + let _ = optional.map_or(5, |x| x + 2); + let _ = bad1(None); + let _ = else_if_option(None); + unop_bad(&None, None); + let _ = longer_body(None); + test_map_or_else(None); + let _ = negative_tests(None); +} diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs new file mode 100644 index 00000000000..dee80d26bd9 --- /dev/null +++ b/tests/ui/option_if_let_else.rs @@ -0,0 +1,92 @@ +// run-rustfix +#![warn(clippy::option_if_let_else)] + +fn bad1(string: Option<&str>) -> (bool, &str) { + if let Some(x) = string { + (true, x) + } else { + (false, "hello") + } +} + +fn else_if_option(string: Option<&str>) -> Option<(bool, &str)> { + if string.is_none() { + None + } else if let Some(x) = string { + Some((true, x)) + } else { + Some((false, "")) + } +} + +fn unop_bad(string: &Option<&str>, mut num: Option) { + let _ = if let Some(s) = *string { s.len() } else { 0 }; + let _ = if let Some(s) = &num { s } else { &0 }; + let _ = if let Some(s) = &mut num { + *s += 1; + s + } else { + &mut 0 + }; + let _ = if let Some(ref s) = num { s } else { &0 }; + let _ = if let Some(mut s) = num { + s += 1; + s + } else { + 0 + }; + let _ = if let Some(ref mut s) = num { + *s += 1; + s + } else { + &mut 0 + }; +} + +fn longer_body(arg: Option) -> u32 { + if let Some(x) = arg { + let y = x * x; + y * y + } else { + 13 + } +} + +fn test_map_or_else(arg: Option) { + let _ = if let Some(x) = arg { + x * x * x * x + } else { + let mut y = 1; + y = (y + 2 / y) / 2; + y = (y + 2 / y) / 2; + y + }; +} + +fn negative_tests(arg: Option) -> u32 { + let _ = if let Some(13) = arg { "unlucky" } else { "lucky" }; + for _ in 0..10 { + let _ = if let Some(x) = arg { + x + } else { + continue; + }; + } + let _ = if let Some(x) = arg { + return x; + } else { + 5 + }; + 7 +} + +fn main() { + let optional = Some(5); + let _ = if let Some(x) = optional { x + 2 } else { 5 }; + let _ = bad1(None); + let _ = else_if_option(None); + unop_bad(&None, None); + let _ = longer_body(None); + test_map_or_else(None); + let _ = negative_tests(None); +} diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr new file mode 100644 index 00000000000..7005850efaf --- /dev/null +++ b/tests/ui/option_if_let_else.stderr @@ -0,0 +1,151 @@ +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:5:5 + | +LL | / if let Some(x) = string { +LL | | (true, x) +LL | | } else { +LL | | (false, "hello") +LL | | } + | |_____^ help: try: `string.map_or((false, "hello"), |x| (true, x))` + | + = 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 + | +LL | } else if let Some(x) = string { + | ____________^ +LL | | Some((true, x)) +LL | | } else { +LL | | Some((false, "")) +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 + | +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 + | +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 + | +LL | let _ = if let Some(s) = &mut num { + | _____________^ +LL | | *s += 1; +LL | | s +LL | | } else { +LL | | &mut 0 +LL | | }; + | |_____^ + | +help: try + | +LL | let _ = num.as_mut().map_or(&mut 0, |s| { +LL | *s += 1; +LL | s +LL | }); + | + +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:31: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 + | +LL | let _ = if let Some(mut s) = num { + | _____________^ +LL | | s += 1; +LL | | s +LL | | } else { +LL | | 0 +LL | | }; + | |_____^ + | +help: try + | +LL | let _ = num.map_or(0, |mut s| { +LL | s += 1; +LL | s +LL | }); + | + +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:38:13 + | +LL | let _ = if let Some(ref mut s) = num { + | _____________^ +LL | | *s += 1; +LL | | s +LL | | } else { +LL | | &mut 0 +LL | | }; + | |_____^ + | +help: try + | +LL | let _ = num.as_mut().map_or(&mut 0, |s| { +LL | *s += 1; +LL | s +LL | }); + | + +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:47:5 + | +LL | / if let Some(x) = arg { +LL | | let y = x * x; +LL | | y * y +LL | | } else { +LL | | 13 +LL | | } + | |_____^ + | +help: try + | +LL | arg.map_or(13, |x| { +LL | let y = x * x; +LL | y * y +LL | }) + | + +error: use Option::map_or_else instead of an if let/else + --> $DIR/option_if_let_else.rs:56:13 + | +LL | let _ = if let Some(x) = arg { + | _____________^ +LL | | x * x * x * x +LL | | } else { +LL | | let mut y = 1; +... | +LL | | y +LL | | }; + | |_____^ + | +help: try + | +LL | let _ = arg.map_or_else(|| { +LL | let mut y = 1; +LL | y = (y + 2 / y) / 2; +LL | y = (y + 2 / y) / 2; +LL | y +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 + | +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 + diff --git a/tests/ui/pattern_type_mismatch/mutability.rs b/tests/ui/pattern_type_mismatch/mutability.rs new file mode 100644 index 00000000000..9b4f2f1f579 --- /dev/null +++ b/tests/ui/pattern_type_mismatch/mutability.rs @@ -0,0 +1,40 @@ +#![allow(clippy::all)] +#![warn(clippy::pattern_type_mismatch)] + +fn main() {} + +fn should_lint() { + let value = &Some(23); + match value { + Some(_) => (), + _ => (), + } + + let value = &mut Some(23); + match value { + Some(_) => (), + _ => (), + } +} + +fn should_not_lint() { + let value = &Some(23); + match value { + &Some(_) => (), + _ => (), + } + match *value { + Some(_) => (), + _ => (), + } + + let value = &mut Some(23); + match value { + &mut Some(_) => (), + _ => (), + } + match *value { + Some(_) => (), + _ => (), + } +} diff --git a/tests/ui/pattern_type_mismatch/mutability.stderr b/tests/ui/pattern_type_mismatch/mutability.stderr new file mode 100644 index 00000000000..3421d568365 --- /dev/null +++ b/tests/ui/pattern_type_mismatch/mutability.stderr @@ -0,0 +1,19 @@ +error: type of pattern does not match the expression type + --> $DIR/mutability.rs:9:9 + | +LL | Some(_) => (), + | ^^^^^^^ + | + = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/mutability.rs:15:9 + | +LL | Some(_) => (), + | ^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&mut _` pattern and adjust the enclosed variable bindings + +error: aborting due to 2 previous errors + diff --git a/tests/ui/pattern_type_mismatch/pattern_alternatives.rs b/tests/ui/pattern_type_mismatch/pattern_alternatives.rs new file mode 100644 index 00000000000..065ea9fb9b5 --- /dev/null +++ b/tests/ui/pattern_type_mismatch/pattern_alternatives.rs @@ -0,0 +1,24 @@ +#![allow(clippy::all)] +#![warn(clippy::pattern_type_mismatch)] + +fn main() {} + +fn alternatives() { + enum Value<'a> { + Unused, + A(&'a Option), + B, + } + let ref_value = &Value::A(&Some(23)); + + // not ok + if let Value::B | Value::A(_) = ref_value {} + if let &Value::B | &Value::A(Some(_)) = ref_value {} + if let Value::B | Value::A(Some(_)) = *ref_value {} + + // ok + if let &Value::B | &Value::A(_) = ref_value {} + if let Value::B | Value::A(_) = *ref_value {} + if let &Value::B | &Value::A(&Some(_)) = ref_value {} + if let Value::B | Value::A(&Some(_)) = *ref_value {} +} diff --git a/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr b/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr new file mode 100644 index 00000000000..d285c93782c --- /dev/null +++ b/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr @@ -0,0 +1,27 @@ +error: type of pattern does not match the expression type + --> $DIR/pattern_alternatives.rs:15:12 + | +LL | if let Value::B | Value::A(_) = ref_value {} + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_alternatives.rs:16:34 + | +LL | if let &Value::B | &Value::A(Some(_)) = ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_alternatives.rs:17:32 + | +LL | if let Value::B | Value::A(Some(_)) = *ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: aborting due to 3 previous errors + diff --git a/tests/ui/pattern_type_mismatch/pattern_structs.rs b/tests/ui/pattern_type_mismatch/pattern_structs.rs new file mode 100644 index 00000000000..417b1c107c5 --- /dev/null +++ b/tests/ui/pattern_type_mismatch/pattern_structs.rs @@ -0,0 +1,45 @@ +#![allow(clippy::all)] +#![warn(clippy::pattern_type_mismatch)] + +fn main() {} + +fn struct_types() { + struct Struct<'a> { + ref_inner: &'a Option, + } + let ref_value = &Struct { ref_inner: &Some(42) }; + + // not ok + let Struct { .. } = ref_value; + if let &Struct { ref_inner: Some(_) } = ref_value {} + if let Struct { ref_inner: Some(_) } = *ref_value {} + + // ok + let &Struct { .. } = ref_value; + let Struct { .. } = *ref_value; + if let &Struct { ref_inner: &Some(_) } = ref_value {} + if let Struct { ref_inner: &Some(_) } = *ref_value {} +} + +fn struct_enum_variants() { + enum StructEnum<'a> { + Empty, + Var { inner_ref: &'a Option }, + } + let ref_value = &StructEnum::Var { inner_ref: &Some(42) }; + + // not ok + if let StructEnum::Var { .. } = ref_value {} + if let StructEnum::Var { inner_ref: Some(_) } = ref_value {} + if let &StructEnum::Var { inner_ref: Some(_) } = ref_value {} + if let StructEnum::Var { inner_ref: Some(_) } = *ref_value {} + if let StructEnum::Empty = ref_value {} + + // ok + if let &StructEnum::Var { .. } = ref_value {} + if let StructEnum::Var { .. } = *ref_value {} + if let &StructEnum::Var { inner_ref: &Some(_) } = ref_value {} + if let StructEnum::Var { inner_ref: &Some(_) } = *ref_value {} + if let &StructEnum::Empty = ref_value {} + if let StructEnum::Empty = *ref_value {} +} diff --git a/tests/ui/pattern_type_mismatch/pattern_structs.stderr b/tests/ui/pattern_type_mismatch/pattern_structs.stderr new file mode 100644 index 00000000000..d428e85b0c9 --- /dev/null +++ b/tests/ui/pattern_type_mismatch/pattern_structs.stderr @@ -0,0 +1,67 @@ +error: type of pattern does not match the expression type + --> $DIR/pattern_structs.rs:13:9 + | +LL | let Struct { .. } = ref_value; + | ^^^^^^^^^^^^^ + | + = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_structs.rs:14:33 + | +LL | if let &Struct { ref_inner: Some(_) } = ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_structs.rs:15:32 + | +LL | if let Struct { ref_inner: Some(_) } = *ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_structs.rs:32:12 + | +LL | if let StructEnum::Var { .. } = ref_value {} + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_structs.rs:33:12 + | +LL | if let StructEnum::Var { inner_ref: Some(_) } = ref_value {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_structs.rs:34:42 + | +LL | if let &StructEnum::Var { inner_ref: Some(_) } = ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_structs.rs:35:41 + | +LL | if let StructEnum::Var { inner_ref: Some(_) } = *ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_structs.rs:36:12 + | +LL | if let StructEnum::Empty = ref_value {} + | ^^^^^^^^^^^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: aborting due to 8 previous errors + diff --git a/tests/ui/pattern_type_mismatch/pattern_tuples.rs b/tests/ui/pattern_type_mismatch/pattern_tuples.rs new file mode 100644 index 00000000000..19504a051d8 --- /dev/null +++ b/tests/ui/pattern_type_mismatch/pattern_tuples.rs @@ -0,0 +1,57 @@ +#![allow(clippy::all)] +#![warn(clippy::pattern_type_mismatch)] + +fn main() {} + +fn tuple_types() { + struct TupleStruct<'a>(&'a Option); + let ref_value = &TupleStruct(&Some(42)); + + // not ok + let TupleStruct(_) = ref_value; + if let &TupleStruct(Some(_)) = ref_value {} + if let TupleStruct(Some(_)) = *ref_value {} + + // ok + let &TupleStruct(_) = ref_value; + let TupleStruct(_) = *ref_value; + if let &TupleStruct(&Some(_)) = ref_value {} + if let TupleStruct(&Some(_)) = *ref_value {} +} + +fn tuple_enum_variants() { + enum TupleEnum<'a> { + Empty, + Var(&'a Option), + } + let ref_value = &TupleEnum::Var(&Some(42)); + + // not ok + if let TupleEnum::Var(_) = ref_value {} + if let &TupleEnum::Var(Some(_)) = ref_value {} + if let TupleEnum::Var(Some(_)) = *ref_value {} + if let TupleEnum::Empty = ref_value {} + + // ok + if let &TupleEnum::Var(_) = ref_value {} + if let TupleEnum::Var(_) = *ref_value {} + if let &TupleEnum::Var(&Some(_)) = ref_value {} + if let TupleEnum::Var(&Some(_)) = *ref_value {} + if let &TupleEnum::Empty = ref_value {} + if let TupleEnum::Empty = *ref_value {} +} + +fn plain_tuples() { + let ref_value = &(&Some(23), &Some(42)); + + // not ok + let (_a, _b) = ref_value; + if let &(_a, Some(_)) = ref_value {} + if let (_a, Some(_)) = *ref_value {} + + // ok + let &(_a, _b) = ref_value; + let (_a, _b) = *ref_value; + if let &(_a, &Some(_)) = ref_value {} + if let (_a, &Some(_)) = *ref_value {} +} diff --git a/tests/ui/pattern_type_mismatch/pattern_tuples.stderr b/tests/ui/pattern_type_mismatch/pattern_tuples.stderr new file mode 100644 index 00000000000..edd0074d00d --- /dev/null +++ b/tests/ui/pattern_type_mismatch/pattern_tuples.stderr @@ -0,0 +1,83 @@ +error: type of pattern does not match the expression type + --> $DIR/pattern_tuples.rs:11:9 + | +LL | let TupleStruct(_) = ref_value; + | ^^^^^^^^^^^^^^ + | + = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_tuples.rs:12:25 + | +LL | if let &TupleStruct(Some(_)) = ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_tuples.rs:13:24 + | +LL | if let TupleStruct(Some(_)) = *ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_tuples.rs:30:12 + | +LL | if let TupleEnum::Var(_) = ref_value {} + | ^^^^^^^^^^^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_tuples.rs:31:28 + | +LL | if let &TupleEnum::Var(Some(_)) = ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_tuples.rs:32:27 + | +LL | if let TupleEnum::Var(Some(_)) = *ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_tuples.rs:33:12 + | +LL | if let TupleEnum::Empty = ref_value {} + | ^^^^^^^^^^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_tuples.rs:48:9 + | +LL | let (_a, _b) = ref_value; + | ^^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_tuples.rs:49:18 + | +LL | if let &(_a, Some(_)) = ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/pattern_tuples.rs:50:17 + | +LL | if let (_a, Some(_)) = *ref_value {} + | ^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: aborting due to 10 previous errors + diff --git a/tests/ui/pattern_type_mismatch/syntax.rs b/tests/ui/pattern_type_mismatch/syntax.rs new file mode 100644 index 00000000000..e89917c41e8 --- /dev/null +++ b/tests/ui/pattern_type_mismatch/syntax.rs @@ -0,0 +1,146 @@ +#![allow(clippy::all)] +#![warn(clippy::pattern_type_mismatch)] + +fn main() {} + +fn syntax_match() { + let ref_value = &Some(&Some(42)); + + // not ok + match ref_value { + Some(_) => (), + None => (), + } + + // ok + match ref_value { + &Some(_) => (), + &None => (), + } + match *ref_value { + Some(_) => (), + None => (), + } +} + +fn syntax_if_let() { + let ref_value = &Some(42); + + // not ok + if let Some(_) = ref_value {} + + // ok + if let &Some(_) = ref_value {} + if let Some(_) = *ref_value {} +} + +fn syntax_while_let() { + let ref_value = &Some(42); + + // not ok + while let Some(_) = ref_value { + break; + } + + // ok + while let &Some(_) = ref_value { + break; + } + while let Some(_) = *ref_value { + break; + } +} + +fn syntax_for() { + let ref_value = &Some(23); + let slice = &[(2, 3), (4, 2)]; + + // not ok + for (_a, _b) in slice.iter() {} + + // ok + for &(_a, _b) in slice.iter() {} +} + +fn syntax_let() { + let ref_value = &(2, 3); + + // not ok + let (_n, _m) = ref_value; + + // ok + let &(_n, _m) = ref_value; + let (_n, _m) = *ref_value; +} + +fn syntax_fn() { + // not ok + fn foo((_a, _b): &(i32, i32)) {} + + // ok + fn foo_ok_1(&(_a, _b): &(i32, i32)) {} +} + +fn syntax_closure() { + fn foo(f: F) + where + F: FnOnce(&(i32, i32)), + { + } + + // not ok + foo(|(_a, _b)| ()); + + // ok + foo(|&(_a, _b)| ()); +} + +fn macro_with_expression() { + macro_rules! matching_macro { + ($e:expr) => { + $e + }; + } + let value = &Some(23); + + // not ok + matching_macro!(match value { + Some(_) => (), + _ => (), + }); + + // ok + matching_macro!(match value { + &Some(_) => (), + _ => (), + }); + matching_macro!(match *value { + Some(_) => (), + _ => (), + }); +} + +fn macro_expansion() { + macro_rules! matching_macro { + ($e:expr) => { + // not ok + match $e { + Some(_) => (), + _ => (), + } + + // ok + match $e { + &Some(_) => (), + _ => (), + } + match *$e { + Some(_) => (), + _ => (), + } + }; + } + + let value = &Some(23); + matching_macro!(value); +} diff --git a/tests/ui/pattern_type_mismatch/syntax.stderr b/tests/ui/pattern_type_mismatch/syntax.stderr new file mode 100644 index 00000000000..5a5186bd4fc --- /dev/null +++ b/tests/ui/pattern_type_mismatch/syntax.stderr @@ -0,0 +1,79 @@ +error: type of pattern does not match the expression type + --> $DIR/syntax.rs:11:9 + | +LL | Some(_) => (), + | ^^^^^^^ + | + = note: `-D clippy::pattern-type-mismatch` implied by `-D warnings` + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/syntax.rs:30:12 + | +LL | if let Some(_) = ref_value {} + | ^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/syntax.rs:41:15 + | +LL | while let Some(_) = ref_value { + | ^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/syntax.rs:59:9 + | +LL | for (_a, _b) in slice.iter() {} + | ^^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/syntax.rs:69:9 + | +LL | let (_n, _m) = ref_value; + | ^^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/syntax.rs:78:12 + | +LL | fn foo((_a, _b): &(i32, i32)) {} + | ^^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/syntax.rs:92:10 + | +LL | foo(|(_a, _b)| ()); + | ^^^^^^^^ + | + = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/syntax.rs:108:9 + | +LL | Some(_) => (), + | ^^^^^^^ + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + +error: type of pattern does not match the expression type + --> $DIR/syntax.rs:128:17 + | +LL | Some(_) => (), + | ^^^^^^^ +... +LL | matching_macro!(value); + | ----------------------- in this macro invocation + | + = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 9 previous errors + diff --git a/tests/ui/range_plus_minus_one.fixed b/tests/ui/range_plus_minus_one.fixed index 6b402114099..19b253b0fe2 100644 --- a/tests/ui/range_plus_minus_one.fixed +++ b/tests/ui/range_plus_minus_one.fixed @@ -7,6 +7,7 @@ fn f() -> usize { } #[warn(clippy::range_plus_one)] +#[warn(clippy::range_minus_one)] fn main() { for _ in 0..2 {} for _ in 0..=2 {} diff --git a/tests/ui/range_plus_minus_one.rs b/tests/ui/range_plus_minus_one.rs index 3cfed4125b3..7d034117547 100644 --- a/tests/ui/range_plus_minus_one.rs +++ b/tests/ui/range_plus_minus_one.rs @@ -7,6 +7,7 @@ fn f() -> usize { } #[warn(clippy::range_plus_one)] +#[warn(clippy::range_minus_one)] fn main() { for _ in 0..2 {} for _ in 0..=2 {} diff --git a/tests/ui/range_plus_minus_one.stderr b/tests/ui/range_plus_minus_one.stderr index f72943a04f2..fb4f1658597 100644 --- a/tests/ui/range_plus_minus_one.stderr +++ b/tests/ui/range_plus_minus_one.stderr @@ -1,5 +1,5 @@ error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:14:14 + --> $DIR/range_plus_minus_one.rs:15:14 | LL | for _ in 0..3 + 1 {} | ^^^^^^^^ help: use: `0..=3` @@ -7,25 +7,25 @@ LL | for _ in 0..3 + 1 {} = note: `-D clippy::range-plus-one` implied by `-D warnings` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:17:14 + --> $DIR/range_plus_minus_one.rs:18:14 | LL | for _ in 0..1 + 5 {} | ^^^^^^^^ help: use: `0..=5` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:20:14 + --> $DIR/range_plus_minus_one.rs:21:14 | LL | for _ in 1..1 + 1 {} | ^^^^^^^^ help: use: `1..=1` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:26:14 + --> $DIR/range_plus_minus_one.rs:27:14 | LL | for _ in 0..(1 + f()) {} | ^^^^^^^^^^^^ help: use: `0..=f()` error: an exclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:30:13 + --> $DIR/range_plus_minus_one.rs:31:13 | LL | let _ = ..=11 - 1; | ^^^^^^^^^ help: use: `..11` @@ -33,25 +33,25 @@ LL | let _ = ..=11 - 1; = note: `-D clippy::range-minus-one` implied by `-D warnings` error: an exclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:31:13 + --> $DIR/range_plus_minus_one.rs:32:13 | LL | let _ = ..=(11 - 1); | ^^^^^^^^^^^ help: use: `..11` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:32:13 + --> $DIR/range_plus_minus_one.rs:33:13 | LL | let _ = (1..11 + 1); | ^^^^^^^^^^^ help: use: `(1..=11)` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:33:13 + --> $DIR/range_plus_minus_one.rs:34:13 | LL | let _ = (f() + 1)..(f() + 1); | ^^^^^^^^^^^^^^^^^^^^ help: use: `((f() + 1)..=f())` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:37:14 + --> $DIR/range_plus_minus_one.rs:38:14 | LL | for _ in 1..ONE + ONE {} | ^^^^^^^^^^^^ help: use: `1..=ONE` diff --git a/tests/ui/redundant_pattern_matching.fixed b/tests/ui/redundant_pattern_matching.fixed index 8b4e2d21331..ce8582d2b22 100644 --- a/tests/ui/redundant_pattern_matching.fixed +++ b/tests/ui/redundant_pattern_matching.fixed @@ -2,7 +2,13 @@ #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] -#![allow(clippy::unit_arg, unused_must_use, clippy::needless_bool, deprecated)] +#![allow( + clippy::unit_arg, + unused_must_use, + clippy::needless_bool, + clippy::match_like_matches_macro, + deprecated +)] fn main() { if Ok::(42).is_ok() {} diff --git a/tests/ui/redundant_pattern_matching.rs b/tests/ui/redundant_pattern_matching.rs index b0904e41b6f..a3a9aa40e3b 100644 --- a/tests/ui/redundant_pattern_matching.rs +++ b/tests/ui/redundant_pattern_matching.rs @@ -2,7 +2,13 @@ #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] -#![allow(clippy::unit_arg, unused_must_use, clippy::needless_bool, deprecated)] +#![allow( + clippy::unit_arg, + unused_must_use, + clippy::needless_bool, + clippy::match_like_matches_macro, + deprecated +)] fn main() { if let Ok(_) = Ok::(42) {} diff --git a/tests/ui/redundant_pattern_matching.stderr b/tests/ui/redundant_pattern_matching.stderr index 51a6f4350d3..25d1476062e 100644 --- a/tests/ui/redundant_pattern_matching.stderr +++ b/tests/ui/redundant_pattern_matching.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:8:12 + --> $DIR/redundant_pattern_matching.rs:14:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` @@ -7,67 +7,67 @@ LL | if let Ok(_) = Ok::(42) {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:10:12 + --> $DIR/redundant_pattern_matching.rs:16:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:12:12 + --> $DIR/redundant_pattern_matching.rs:18: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.rs:14:12 + --> $DIR/redundant_pattern_matching.rs:20: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.rs:16:12 + --> $DIR/redundant_pattern_matching.rs:22: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.rs:22:15 + --> $DIR/redundant_pattern_matching.rs:28: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.rs:24:15 + --> $DIR/redundant_pattern_matching.rs:30: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.rs:26:15 + --> $DIR/redundant_pattern_matching.rs:32:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try this: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:28:15 + --> $DIR/redundant_pattern_matching.rs:34:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:30:15 + --> $DIR/redundant_pattern_matching.rs:36:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:33:15 + --> $DIR/redundant_pattern_matching.rs:39:15 | LL | while let Some(_) = v.pop() { | ----------^^^^^^^---------- help: try this: `while v.pop().is_some()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:49:5 + --> $DIR/redundant_pattern_matching.rs:55:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -76,7 +76,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:54:5 + --> $DIR/redundant_pattern_matching.rs:60:5 | LL | / match Ok::(42) { LL | | Ok(_) => false, @@ -85,7 +85,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_err()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:59:5 + --> $DIR/redundant_pattern_matching.rs:65:5 | LL | / match Err::(42) { LL | | Ok(_) => false, @@ -94,7 +94,7 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:64:5 + --> $DIR/redundant_pattern_matching.rs:70:5 | LL | / match Err::(42) { LL | | Ok(_) => true, @@ -103,7 +103,7 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_ok()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:69:5 + --> $DIR/redundant_pattern_matching.rs:75:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -112,7 +112,7 @@ LL | | }; | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:74:5 + --> $DIR/redundant_pattern_matching.rs:80:5 | LL | / match None::<()> { LL | | Some(_) => false, @@ -121,7 +121,7 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:79:13 + --> $DIR/redundant_pattern_matching.rs:85:13 | LL | let _ = match None::<()> { | _____________^ @@ -131,61 +131,61 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:84:20 + --> $DIR/redundant_pattern_matching.rs:90:20 | LL | let _ = if let Ok(_) = Ok::(4) { true } else { false }; | -------^^^^^--------------------- help: try this: `if Ok::(4).is_ok()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:87:20 + --> $DIR/redundant_pattern_matching.rs:93:20 | LL | let x = 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.rs:93:20 + --> $DIR/redundant_pattern_matching.rs:99: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.rs:95:19 + --> $DIR/redundant_pattern_matching.rs:101:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try this: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:97:19 + --> $DIR/redundant_pattern_matching.rs:103:19 | LL | } else if let Ok(_) = gen_res() { | -------^^^^^------------ help: try this: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:99:19 + --> $DIR/redundant_pattern_matching.rs:105:19 | LL | } else if let Err(_) = gen_res() { | -------^^^^^^------------ help: try this: `if gen_res().is_err()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:132:19 + --> $DIR/redundant_pattern_matching.rs:138:19 | LL | while let Some(_) = r#try!(result_opt()) {} | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:133:16 + --> $DIR/redundant_pattern_matching.rs:139:16 | LL | if let Some(_) = r#try!(result_opt()) {} | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:139:12 + --> $DIR/redundant_pattern_matching.rs:145:12 | LL | if let Some(_) = m!() {} | -------^^^^^^^------- help: try this: `if m!().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:140:15 + --> $DIR/redundant_pattern_matching.rs:146:15 | LL | while let Some(_) = m!() {} | ----------^^^^^^^------- help: try this: `while m!().is_some()` diff --git a/tests/ui/redundant_pattern_matching_const_result.fixed b/tests/ui/redundant_pattern_matching_const_result.fixed index 8a81e92f04a..de3fe00d5fa 100644 --- a/tests/ui/redundant_pattern_matching_const_result.fixed +++ b/tests/ui/redundant_pattern_matching_const_result.fixed @@ -2,7 +2,7 @@ #![feature(const_result)] #![warn(clippy::redundant_pattern_matching)] -#![allow(unused)] +#![allow(clippy::match_like_matches_macro, unused)] // Test that results are linted with the feature enabled. diff --git a/tests/ui/redundant_pattern_matching_const_result.rs b/tests/ui/redundant_pattern_matching_const_result.rs index 1cd515441d1..b77969d53d9 100644 --- a/tests/ui/redundant_pattern_matching_const_result.rs +++ b/tests/ui/redundant_pattern_matching_const_result.rs @@ -2,7 +2,7 @@ #![feature(const_result)] #![warn(clippy::redundant_pattern_matching)] -#![allow(unused)] +#![allow(clippy::match_like_matches_macro, unused)] // Test that results are linted with the feature enabled. diff --git a/tests/ui/regex.rs b/tests/ui/regex.rs index b523fa5b711..9767e5bf76a 100644 --- a/tests/ui/regex.rs +++ b/tests/ui/regex.rs @@ -1,5 +1,5 @@ #![allow(unused)] -#![warn(clippy::invalid_regex, clippy::trivial_regex, clippy::regex_macro)] +#![warn(clippy::invalid_regex, clippy::trivial_regex)] extern crate regex; diff --git a/tests/ui/repeat_once.fixed b/tests/ui/repeat_once.fixed new file mode 100644 index 00000000000..a637c22fbcd --- /dev/null +++ b/tests/ui/repeat_once.fixed @@ -0,0 +1,16 @@ +// run-rustfix +#![warn(clippy::repeat_once)] +#[allow(unused, clippy::many_single_char_names, clippy::redundant_clone)] +fn main() { + const N: usize = 1; + let s = "str"; + let string = "String".to_string(); + let slice = [1; 5]; + + let a = [1; 5].to_vec(); + let b = slice.to_vec(); + let c = "hello".to_string(); + let d = "hi".to_string(); + let e = s.to_string(); + let f = string.clone(); +} diff --git a/tests/ui/repeat_once.rs b/tests/ui/repeat_once.rs new file mode 100644 index 00000000000..d99ca1b5b55 --- /dev/null +++ b/tests/ui/repeat_once.rs @@ -0,0 +1,16 @@ +// run-rustfix +#![warn(clippy::repeat_once)] +#[allow(unused, clippy::many_single_char_names, clippy::redundant_clone)] +fn main() { + const N: usize = 1; + let s = "str"; + let string = "String".to_string(); + let slice = [1; 5]; + + let a = [1; 5].repeat(1); + let b = slice.repeat(1); + let c = "hello".repeat(N); + let d = "hi".repeat(1); + let e = s.repeat(1); + let f = string.repeat(1); +} diff --git a/tests/ui/repeat_once.stderr b/tests/ui/repeat_once.stderr new file mode 100644 index 00000000000..915eea3bfc6 --- /dev/null +++ b/tests/ui/repeat_once.stderr @@ -0,0 +1,40 @@ +error: calling `repeat(1)` on slice + --> $DIR/repeat_once.rs:10:13 + | +LL | let a = [1; 5].repeat(1); + | ^^^^^^^^^^^^^^^^ help: consider using `.to_vec()` instead: `[1; 5].to_vec()` + | + = note: `-D clippy::repeat-once` implied by `-D warnings` + +error: calling `repeat(1)` on slice + --> $DIR/repeat_once.rs:11:13 + | +LL | let b = slice.repeat(1); + | ^^^^^^^^^^^^^^^ help: consider using `.to_vec()` instead: `slice.to_vec()` + +error: calling `repeat(1)` on str + --> $DIR/repeat_once.rs:12:13 + | +LL | let c = "hello".repeat(N); + | ^^^^^^^^^^^^^^^^^ help: consider using `.to_string()` instead: `"hello".to_string()` + +error: calling `repeat(1)` on str + --> $DIR/repeat_once.rs:13:13 + | +LL | let d = "hi".repeat(1); + | ^^^^^^^^^^^^^^ help: consider using `.to_string()` instead: `"hi".to_string()` + +error: calling `repeat(1)` on str + --> $DIR/repeat_once.rs:14:13 + | +LL | let e = s.repeat(1); + | ^^^^^^^^^^^ help: consider using `.to_string()` instead: `s.to_string()` + +error: calling `repeat(1)` on a string literal + --> $DIR/repeat_once.rs:15:13 + | +LL | let f = string.repeat(1); + | ^^^^^^^^^^^^^^^^ help: consider using `.clone()` instead: `string.clone()` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/single_match_else.rs b/tests/ui/single_match_else.rs index 34193be0b75..b624a41a29b 100644 --- a/tests/ui/single_match_else.rs +++ b/tests/ui/single_match_else.rs @@ -1,4 +1,6 @@ #![warn(clippy::single_match_else)] +#![allow(clippy::needless_return)] +#![allow(clippy::no_effect)] enum ExprNode { ExprAddrOf, @@ -30,6 +32,55 @@ macro_rules! unwrap_addr { }; } +#[rustfmt::skip] fn main() { unwrap_addr!(ExprNode::Unicorns); + + // + // don't lint single exprs/statements + // + + // don't lint here + match Some(1) { + Some(a) => println!("${:?}", a), + None => return, + } + + // don't lint here + match Some(1) { + Some(a) => println!("${:?}", a), + None => { + return + }, + } + + // don't lint here + match Some(1) { + Some(a) => println!("${:?}", a), + None => { + return; + }, + } + + // + // lint multiple exprs/statements "else" blocks + // + + // lint here + match Some(1) { + Some(a) => println!("${:?}", a), + None => { + println!("else block"); + return + }, + } + + // lint here + match Some(1) { + Some(a) => println!("${:?}", a), + None => { + println!("else block"); + return; + }, + } } diff --git a/tests/ui/single_match_else.stderr b/tests/ui/single_match_else.stderr index 59861d46eb3..3a07c2ec542 100644 --- a/tests/ui/single_match_else.stderr +++ b/tests/ui/single_match_else.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match_else.rs:12:5 + --> $DIR/single_match_else.rs:14:5 | LL | / match ExprNode::Butterflies { LL | | ExprNode::ExprAddrOf => Some(&NODE), @@ -19,5 +19,45 @@ LL | None LL | } | -error: aborting due to previous error +error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` + --> $DIR/single_match_else.rs:70:5 + | +LL | / match Some(1) { +LL | | Some(a) => println!("${:?}", a), +LL | | None => { +LL | | println!("else block"); +LL | | return +LL | | }, +LL | | } + | |_____^ + | +help: try this + | +LL | if let Some(a) = Some(1) { println!("${:?}", a) } else { +LL | println!("else block"); +LL | return +LL | } + | + +error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let` + --> $DIR/single_match_else.rs:79:5 + | +LL | / match Some(1) { +LL | | Some(a) => println!("${:?}", a), +LL | | None => { +LL | | println!("else block"); +LL | | return; +LL | | }, +LL | | } + | |_____^ + | +help: try this + | +LL | if let Some(a) = Some(1) { println!("${:?}", a) } else { +LL | println!("else block"); +LL | return; +LL | } + | + +error: aborting due to 3 previous errors diff --git a/tests/ui/type_repetition_in_bounds.rs b/tests/ui/type_repetition_in_bounds.rs index 8b538be762b..766190f2099 100644 --- a/tests/ui/type_repetition_in_bounds.rs +++ b/tests/ui/type_repetition_in_bounds.rs @@ -1,4 +1,6 @@ -#[deny(clippy::type_repetition_in_bounds)] +#![deny(clippy::type_repetition_in_bounds)] + +use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; pub fn foo(_t: T) where @@ -16,4 +18,55 @@ where unimplemented!(); } +// Threshold test (see #4380) +trait LintBounds +where + Self: Clone, + Self: Copy + Default + Ord, + Self: Add + AddAssign + Sub + SubAssign, + Self: Mul + MulAssign + Div + DivAssign, +{ +} + +trait LotsOfBounds +where + Self: Clone + Copy + Default + Ord, + Self: Add + AddAssign + Sub + SubAssign, + Self: Mul + MulAssign + Div + DivAssign, +{ +} + +// Generic distinction (see #4323) +mod issue4323 { + pub struct Foo(A); + pub struct Bar { + a: Foo, + b: Foo, + } + + impl Unpin for Bar + where + Foo: Unpin, + Foo: Unpin, + { + } +} + +// Extern macros shouldn't lint (see #4326) +extern crate serde; +mod issue4326 { + use serde::{Deserialize, Serialize}; + + trait Foo {} + impl Foo for String {} + + #[derive(Debug, Serialize, Deserialize)] + struct Bar + where + S: Foo, + { + foo: S, + } +} + fn main() {} diff --git a/tests/ui/type_repetition_in_bounds.stderr b/tests/ui/type_repetition_in_bounds.stderr index 4264e2e10bf..148c19c7d07 100644 --- a/tests/ui/type_repetition_in_bounds.stderr +++ b/tests/ui/type_repetition_in_bounds.stderr @@ -1,15 +1,23 @@ error: this type has already been used as a bound predicate - --> $DIR/type_repetition_in_bounds.rs:6:5 + --> $DIR/type_repetition_in_bounds.rs:8:5 | LL | T: Clone, | ^^^^^^^^ | note: the lint level is defined here - --> $DIR/type_repetition_in_bounds.rs:1:8 + --> $DIR/type_repetition_in_bounds.rs:1:9 | -LL | #[deny(clippy::type_repetition_in_bounds)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(clippy::type_repetition_in_bounds)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: consider combining the bounds: `T: Copy + Clone` -error: aborting due to previous error +error: this type has already been used as a bound predicate + --> $DIR/type_repetition_in_bounds.rs:25:5 + | +LL | Self: Copy + Default + Ord, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider combining the bounds: `Self: Clone + Copy + Default + Ord` + +error: aborting due to 2 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 diff --git a/tests/ui/unnecessary_sort_by.fixed b/tests/ui/unnecessary_sort_by.fixed index 779fd57707a..c017d1cf9a4 100644 --- a/tests/ui/unnecessary_sort_by.fixed +++ b/tests/ui/unnecessary_sort_by.fixed @@ -2,11 +2,11 @@ use std::cmp::Reverse; -fn id(x: isize) -> isize { - x -} +fn unnecessary_sort_by() { + fn id(x: isize) -> isize { + x + } -fn main() { let mut vec: Vec = vec![3, 6, 1, 2, 5]; // Forward examples vec.sort(); @@ -24,3 +24,41 @@ fn main() { vec.sort_by(|_, b| b.cmp(c)); vec.sort_unstable_by(|a, _| a.cmp(c)); } + +// Should not be linted to avoid hitting https://github.com/rust-lang/rust/issues/34162 +mod issue_5754 { + struct Test(String); + + #[derive(PartialOrd, Ord, PartialEq, Eq)] + struct Wrapper<'a>(&'a str); + + impl Test { + fn name(&self) -> &str { + &self.0 + } + + fn wrapped(&self) -> Wrapper<'_> { + Wrapper(&self.0) + } + } + + pub fn test() { + let mut args: Vec = vec![]; + + // Forward + args.sort_by(|a, b| a.name().cmp(b.name())); + args.sort_by(|a, b| a.wrapped().cmp(&b.wrapped())); + args.sort_unstable_by(|a, b| a.name().cmp(b.name())); + args.sort_unstable_by(|a, b| a.wrapped().cmp(&b.wrapped())); + // Reverse + args.sort_by(|a, b| b.name().cmp(a.name())); + args.sort_by(|a, b| b.wrapped().cmp(&a.wrapped())); + args.sort_unstable_by(|a, b| b.name().cmp(a.name())); + args.sort_unstable_by(|a, b| b.wrapped().cmp(&a.wrapped())); + } +} + +fn main() { + unnecessary_sort_by(); + issue_5754::test(); +} diff --git a/tests/ui/unnecessary_sort_by.rs b/tests/ui/unnecessary_sort_by.rs index 0485a5630af..1929c72b2f2 100644 --- a/tests/ui/unnecessary_sort_by.rs +++ b/tests/ui/unnecessary_sort_by.rs @@ -2,11 +2,11 @@ use std::cmp::Reverse; -fn id(x: isize) -> isize { - x -} +fn unnecessary_sort_by() { + fn id(x: isize) -> isize { + x + } -fn main() { let mut vec: Vec = vec![3, 6, 1, 2, 5]; // Forward examples vec.sort_by(|a, b| a.cmp(b)); @@ -24,3 +24,41 @@ fn main() { vec.sort_by(|_, b| b.cmp(c)); vec.sort_unstable_by(|a, _| a.cmp(c)); } + +// Should not be linted to avoid hitting https://github.com/rust-lang/rust/issues/34162 +mod issue_5754 { + struct Test(String); + + #[derive(PartialOrd, Ord, PartialEq, Eq)] + struct Wrapper<'a>(&'a str); + + impl Test { + fn name(&self) -> &str { + &self.0 + } + + fn wrapped(&self) -> Wrapper<'_> { + Wrapper(&self.0) + } + } + + pub fn test() { + let mut args: Vec = vec![]; + + // Forward + args.sort_by(|a, b| a.name().cmp(b.name())); + args.sort_by(|a, b| a.wrapped().cmp(&b.wrapped())); + args.sort_unstable_by(|a, b| a.name().cmp(b.name())); + args.sort_unstable_by(|a, b| a.wrapped().cmp(&b.wrapped())); + // Reverse + args.sort_by(|a, b| b.name().cmp(a.name())); + args.sort_by(|a, b| b.wrapped().cmp(&a.wrapped())); + args.sort_unstable_by(|a, b| b.name().cmp(a.name())); + args.sort_unstable_by(|a, b| b.wrapped().cmp(&a.wrapped())); + } +} + +fn main() { + unnecessary_sort_by(); + issue_5754::test(); +} diff --git a/tests/ui/unnested_or_patterns3.rs b/tests/ui/unnested_or_patterns3.rs new file mode 100644 index 00000000000..6bd35057bfa --- /dev/null +++ b/tests/ui/unnested_or_patterns3.rs @@ -0,0 +1,6 @@ +#![warn(clippy::unnested_or_patterns)] + +// Test that `unnested_or_patterns` does not trigger without enabling `or_patterns` +fn main() { + if let (0, 1) | (0, 2) | (0, 3) = (0, 0) {} +} From 126790999a128a880ca276c49afd2927a66ffbbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Mon, 30 Mar 2020 11:02:14 +0200 Subject: [PATCH 08/36] new lint: Returning unit from closures expecting Ord This lint catches cases where the last statement of a closure expecting an instance of Ord has a trailing semi-colon. It compiles since the closure ends up return () which also implements Ord but causes unexpected results in cases such as sort_by_key. Fixes #5080 reprise: rebase, update and address all concerns --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 5 + clippy_lints/src/unit_return_expecting_ord.rs | 177 ++++++++++++++++++ src/lintlist/mod.rs | 7 + tests/ui/unit_return_expecting_ord.rs | 36 ++++ tests/ui/unit_return_expecting_ord.stderr | 39 ++++ 6 files changed, 265 insertions(+) create mode 100644 clippy_lints/src/unit_return_expecting_ord.rs create mode 100644 tests/ui/unit_return_expecting_ord.rs create mode 100644 tests/ui/unit_return_expecting_ord.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d08b44ba40..1c927b5f83a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1679,6 +1679,7 @@ Released 2018-09-13 [`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init [`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 [`unknown_clippy_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#unknown_clippy_lints [`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 diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 32e79317f82..7a4ca3902b3 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -300,6 +300,7 @@ mod trivially_copy_pass_by_ref; mod try_err; mod types; mod unicode; +mod unit_return_expecting_ord; mod unnamed_address; mod unnecessary_sort_by; mod unnested_or_patterns; @@ -826,6 +827,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unicode::NON_ASCII_LITERAL, &unicode::UNICODE_NOT_NFC, &unicode::ZERO_WIDTH_SPACE, + &unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD, &unnamed_address::FN_ADDRESS_COMPARISONS, &unnamed_address::VTABLE_ADDRESS_COMPARISONS, &unnecessary_sort_by::UNNECESSARY_SORT_BY, @@ -891,6 +893,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box attrs::Attributes); store.register_late_pass(|| box blocks_in_if_conditions::BlocksInIfConditions); store.register_late_pass(|| box unicode::Unicode); + store.register_late_pass(|| box unit_return_expecting_ord::UnitReturnExpectingOrd); store.register_late_pass(|| box strings::StringAdd); store.register_late_pass(|| box implicit_return::ImplicitReturn); store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub); @@ -1436,6 +1439,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::UNNECESSARY_CAST), LintId::of(&types::VEC_BOX), LintId::of(&unicode::ZERO_WIDTH_SPACE), + LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), @@ -1692,6 +1696,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::CAST_REF_TO_MUT), LintId::of(&types::UNIT_CMP), LintId::of(&unicode::ZERO_WIDTH_SPACE), + LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs new file mode 100644 index 00000000000..fceb885516b --- /dev/null +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -0,0 +1,177 @@ +use crate::utils::{get_trait_def_id, paths, span_lint, span_lint_and_help}; +use if_chain::if_chain; +use rustc_hir::def_id::DefId; +use rustc_hir::{Expr, ExprKind, StmtKind}; +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}; + +declare_clippy_lint! { + /// **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 + /// 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 + /// way of specifying this without triggering needless_return lint + /// + /// **Example:** + /// + /// ```rust + /// let mut twins = vec!((1,1), (2,2)); + /// twins.sort_by_key(|x| { x.1; }); + /// ``` + pub UNIT_RETURN_EXPECTING_ORD, + correctness, + "fn arguments of type Fn(...) -> Ord returning the unit type ()." +} + +declare_lint_pass!(UnitReturnExpectingOrd => [UNIT_RETURN_EXPECTING_ORD]); + +fn get_trait_predicates_for_trait_id<'tcx>( + cx: &LateContext<'tcx>, + generics: GenericPredicates<'tcx>, + trait_id: Option, +) -> Vec> { + let mut preds = Vec::new(); + for (pred, _) in generics.predicates { + if_chain! { + if let PredicateKind::Trait(poly_trait_pred, _) = pred.kind(); + let trait_pred = cx.tcx.erase_late_bound_regions(&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); + } + } + } + preds +} + +fn get_projection_pred<'tcx>( + cx: &LateContext<'tcx>, + generics: GenericPredicates<'tcx>, + pred: TraitPredicate<'tcx>, +) -> Option> { + generics.predicates.iter().find_map(|(proj_pred, _)| { + if let PredicateKind::Projection(proj_pred) = proj_pred.kind() { + let projection_pred = cx.tcx.erase_late_bound_regions(proj_pred); + if projection_pred.projection_ty.substs == pred.trait_ref.substs { + return Some(projection_pred); + } + } + None + }) +} + +fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Vec<(usize, String)> { + let mut args_to_check = Vec::new(); + if let Some(def_id) = cx.tables().type_dependent_def_id(expr.hir_id) { + 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 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 + // The trait `rustc::ty::TypeFoldable<'_>` is not implemented for `&[&rustc::ty::TyS<'_>]` + let inputs_output = cx.tcx.erase_late_bound_regions(&fn_sig.inputs_and_output()); + inputs_output + .iter() + .rev() + .skip(1) + .rev() + .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| ord.self_ty() == return_ty_pred.ty) { + args_to_check.push((i, "Ord".to_string())); + } else if partial_ord_preds.iter().any(|pord| pord.self_ty() == return_ty_pred.ty) { + args_to_check.push((i, "PartialOrd".to_string())); + } + } + } + } + }); + } + args_to_check +} + +fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Span, Option)> { + if_chain! { + if let ExprKind::Closure(_, _fn_decl, body_id, span, _) = arg.kind; + if let ty::Closure(_def_id, substs) = &cx.tables().node_type(arg.hir_id).kind; + let ret_ty = substs.as_closure().sig().output(); + let ty = cx.tcx.erase_late_bound_regions(&ret_ty); + if ty.is_unit(); + then { + 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(); + if let StmtKind::Semi(_) = stmt.kind; + then { + let data = stmt.span.data(); + // Make a span out of the semicolon for the help message + Some((span, Some(Span::new(data.hi-BytePos(1), data.hi, data.ctxt)))) + } else { + Some((span, None)) + } + } + } else { + None + } + } +} + +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 { + let arg_indices = get_args_to_check(cx, expr); + for (i, trait_name) in arg_indices { + if i < args.len() { + match check_arg(cx, &args[i]) { + Some((span, None)) => { + span_lint( + cx, + UNIT_RETURN_EXPECTING_ORD, + span, + &format!( + "this closure returns \ + the unit type which also implements {}", + trait_name + ), + ); + }, + Some((span, Some(last_semi))) => { + span_lint_and_help( + cx, + UNIT_RETURN_EXPECTING_ORD, + span, + &format!( + "this closure returns \ + the unit type which also implements {}", + trait_name + ), + Some(last_semi), + &"probably caused by this trailing semicolon".to_string(), + ); + }, + None => {}, + } + } + } + } + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index b89a8712862..96b004904aa 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2292,6 +2292,13 @@ pub static ref ALL_LINTS: Vec = vec![ deprecation: None, module: "types", }, + Lint { + name: "unit_return_expecting_ord", + group: "correctness", + desc: "fn arguments of type Fn(...) -> Ord returning the unit type ().", + deprecation: None, + module: "unit_return_expecting_ord", + }, Lint { name: "unknown_clippy_lints", group: "style", diff --git a/tests/ui/unit_return_expecting_ord.rs b/tests/ui/unit_return_expecting_ord.rs new file mode 100644 index 00000000000..bdb4710cc69 --- /dev/null +++ b/tests/ui/unit_return_expecting_ord.rs @@ -0,0 +1,36 @@ +#![warn(clippy::unit_return_expecting_ord)] +#![allow(clippy::needless_return)] +#![allow(clippy::unused_unit)] +#![feature(is_sorted)] + +struct Struct { + field: isize, +} + +fn double(i: isize) -> isize { + i * 2 +} + +fn unit(_i: isize) {} + +fn main() { + let mut structs = vec![Struct { field: 2 }, Struct { field: 1 }]; + structs.sort_by_key(|s| { + double(s.field); + }); + structs.sort_by_key(|s| double(s.field)); + structs.is_sorted_by_key(|s| { + double(s.field); + }); + structs.is_sorted_by_key(|s| { + if s.field > 0 { + () + } else { + return (); + } + }); + structs.sort_by_key(|s| { + return double(s.field); + }); + structs.sort_by_key(|s| unit(s.field)); +} diff --git a/tests/ui/unit_return_expecting_ord.stderr b/tests/ui/unit_return_expecting_ord.stderr new file mode 100644 index 00000000000..e63d5874609 --- /dev/null +++ b/tests/ui/unit_return_expecting_ord.stderr @@ -0,0 +1,39 @@ +error: this closure returns the unit type which also implements Ord + --> $DIR/unit_return_expecting_ord.rs:18:25 + | +LL | structs.sort_by_key(|s| { + | ^^^ + | + = note: `-D clippy::unit-return-expecting-ord` implied by `-D warnings` +help: probably caused by this trailing semicolon + --> $DIR/unit_return_expecting_ord.rs:19:24 + | +LL | double(s.field); + | ^ + +error: this closure returns the unit type which also implements PartialOrd + --> $DIR/unit_return_expecting_ord.rs:22:30 + | +LL | structs.is_sorted_by_key(|s| { + | ^^^ + | +help: probably caused by this trailing semicolon + --> $DIR/unit_return_expecting_ord.rs:23:24 + | +LL | double(s.field); + | ^ + +error: this closure returns the unit type which also implements PartialOrd + --> $DIR/unit_return_expecting_ord.rs:25:30 + | +LL | structs.is_sorted_by_key(|s| { + | ^^^ + +error: this closure returns the unit type which also implements Ord + --> $DIR/unit_return_expecting_ord.rs:35:25 + | +LL | structs.sort_by_key(|s| unit(s.field)); + | ^^^ + +error: aborting due to 4 previous errors + From e83b3eb9930ab527451edaaa6f524acd26c1bf1c Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Tue, 14 Jul 2020 09:20:19 -0700 Subject: [PATCH 09/36] formatting nits --- clippy_lints/src/methods/mod.rs | 2 +- tests/ui/iter_nth_zero.stderr | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) 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 From f2f99be2ff619aeb67259b73b51992d026fc11fe Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 8 Jul 2020 20:03:37 +1000 Subject: [PATCH 10/36] Remove lots of `Symbol::as_str()` calls. In various ways, such as changing functions to take a `Symbol` instead of a `&str`. --- clippy_lints/src/attrs.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index ef01364b7d9..c29432bf933 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -421,7 +421,11 @@ fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMet .iter() .map(|l| Symbol::intern(&l.name_lower())) .collect::>(); - let sugg = find_best_match_for_name(symbols.iter(), &format!("clippy::{}", name_lower), None); + let sugg = find_best_match_for_name( + symbols.iter(), + Symbol::intern(&format!("clippy::{}", name_lower)), + None, + ); if lint_name.chars().any(char::is_uppercase) && lint_store.find_lints(&format!("clippy::{}", name_lower)).is_ok() { From 29de25b8a26aae3d37d935c437f5afb69f7ccbb2 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 2 Jul 2020 23:56:17 +0200 Subject: [PATCH 11/36] const_eval_resolve --- clippy_lints/src/consts.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index 2f963dfcf8b..6ba4201b2c2 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -332,7 +332,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { let result = self .lcx .tcx - .const_eval_resolve(self.param_env, def_id, substs, None, None) + .const_eval_resolve(self.param_env, ty::WithOptParam::dummy(def_id), substs, None, None) .ok() .map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?; let result = miri_to_const(&result); From c5b9463d266a084f40ccec85a7587a8c375c179b Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 15 Jul 2020 10:50:54 +0200 Subject: [PATCH 12/36] improve naming --- clippy_lints/src/consts.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index 6ba4201b2c2..891cb69bb56 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -332,7 +332,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { let result = self .lcx .tcx - .const_eval_resolve(self.param_env, ty::WithOptParam::dummy(def_id), substs, None, None) + .const_eval_resolve(self.param_env, ty::WithOptConstParam::dummy(def_id), substs, None, None) .ok() .map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?; let result = miri_to_const(&result); From bf3104ec24f788538fd1db84bf3b8819c303418c Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 15 Jul 2020 10:55:41 +0200 Subject: [PATCH 13/36] WithOptConstParam::dummy -> WithOptConstParam::unknown --- clippy_lints/src/consts.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index 891cb69bb56..e6ef54f528f 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -332,7 +332,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { let result = self .lcx .tcx - .const_eval_resolve(self.param_env, ty::WithOptConstParam::dummy(def_id), substs, None, None) + .const_eval_resolve(self.param_env, ty::WithOptConstParam::unknown(def_id), substs, None, None) .ok() .map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?; let result = miri_to_const(&result); From a0640457a912720a5473d7feff40576a2f97df1e Mon Sep 17 00:00:00 2001 From: Leo Meira Vital Date: Mon, 13 Jul 2020 01:57:19 -0300 Subject: [PATCH 14/36] Removing snippet from SHADOW_UNRELATED message. --- clippy_lints/src/shadow.rs | 6 +----- tests/ui/shadow.stderr | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 194786c5c41..fab13c8c124 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -295,11 +295,7 @@ fn lint_shadow<'tcx>( cx, SHADOW_UNRELATED, pattern_span, - &format!( - "`{}` is shadowed by `{}`", - snippet(cx, pattern_span, "_"), - snippet(cx, expr.span, "..") - ), + &format!("`{}` is being shadowed", snippet(cx, pattern_span, "_")), |diag| { diag.span_note(expr.span, "initialization happens here"); diag.span_note(prev_span, "previous binding is here"); diff --git a/tests/ui/shadow.stderr b/tests/ui/shadow.stderr index 7fa58cf7649..8a831375b41 100644 --- a/tests/ui/shadow.stderr +++ b/tests/ui/shadow.stderr @@ -104,7 +104,7 @@ note: previous binding is here LL | let x = (1, x); | ^ -error: `x` is shadowed by `y` +error: `x` is being shadowed --> $DIR/shadow.rs:34:9 | LL | let x = y; From ef896faa0153d0d96b6d6eafe7dd53b178525a25 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 16 Jul 2020 13:44:58 +0200 Subject: [PATCH 15/36] Fix deploy script for beta deployment Since the beta/ directory already exists, we can't copy the complete master dir --- .github/deploy.sh | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/.github/deploy.sh b/.github/deploy.sh index 3f425e5b725..e0a95fb9f36 100644 --- a/.github/deploy.sh +++ b/.github/deploy.sh @@ -19,7 +19,7 @@ fi if [[ $BETA = "true" ]]; then echo "Update documentation for the beta release" - cp -r out/master out/beta + cp -r out/master/* out/beta fi # Generate version index that is shown as root index page @@ -33,12 +33,11 @@ cd out git config user.name "GHA CI" git config user.email "gha@ci.invalid" -if git diff --exit-code --quiet; then - echo "No changes to the output on this push; exiting." - exit 0 -fi - if [[ -n $TAG_NAME ]]; then + if git diff --exit-code --quiet -- $TAG_NAME/; then + echo "No changes to the output on this push; exiting." + exit 0 + fi # Add the new dir git add "$TAG_NAME" # Update the symlink @@ -47,9 +46,17 @@ if [[ -n $TAG_NAME ]]; then git add versions.json git commit -m "Add documentation for ${TAG_NAME} release: ${SHA}" elif [[ $BETA = "true" ]]; then + if git diff --exit-code --quiet -- beta/; then + echo "No changes to the output on this push; exiting." + exit 0 + fi git add beta git commit -m "Automatic deploy to GitHub Pages (beta): ${SHA}" else + if git diff --exit-code --quiet; then + echo "No changes to the output on this push; exiting." + exit 0 + fi git add . git commit -m "Automatic deploy to GitHub Pages: ${SHA}" fi From c65eb4d66314d22d85cf2e58ff20ec1ca7404751 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 16 Jul 2020 14:42:13 +0200 Subject: [PATCH 16/36] Track tag files, before checking for the diff --- .github/deploy.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/deploy.sh b/.github/deploy.sh index e0a95fb9f36..e85e8874ba6 100644 --- a/.github/deploy.sh +++ b/.github/deploy.sh @@ -34,6 +34,8 @@ git config user.name "GHA CI" git config user.email "gha@ci.invalid" if [[ -n $TAG_NAME ]]; then + # track files, so that the following check works + git add --intent-to-add "$TAG_NAME" if git diff --exit-code --quiet -- $TAG_NAME/; then echo "No changes to the output on this push; exiting." exit 0 From cf383cf48aa1bc09c50ae7d3599254c82b7dc0bf Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 16 Jul 2020 15:34:41 +0200 Subject: [PATCH 17/36] Update changelog to beta-1.46 --- CHANGELOG.md | 68 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c927b5f83a..b9d0a15b755 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,73 @@ document. ## Unreleased / In Rust Nightly -[7ea7cd1...master](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...master) +[c2c07fa...master](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...master) + +## Rust 1.46 + +Current beta, release 2020-08-27 + +[7ea7cd1...c2c07fa](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...master) + +### New lints + +* [`unnested_or_patterns`] [#5378](https://github.com/rust-lang/rust-clippy/pull/5378) +* [`iter_next_slice`] [#5597](https://github.com/rust-lang/rust-clippy/pull/5597) +* [`unnecessary_sort_by`] [#5623](https://github.com/rust-lang/rust-clippy/pull/5623) +* [`vec_resize_to_zero`] [#5637](https://github.com/rust-lang/rust-clippy/pull/5637) + +### Moves and Deprecations + +* Move [`cast_ptr_alignment`] to pedantic [#5667](https://github.com/rust-lang/rust-clippy/pull/5667) + +### Enhancements + +* Improve [`mem_replace_with_uninit`] lint [#5695](https://github.com/rust-lang/rust-clippy/pull/5695) + +### False Positive Fixes + +* [`len_zero`]: Avoid linting ranges when the `range_is_empty` feature is not enabled + [#5656](https://github.com/rust-lang/rust-clippy/pull/5656) +* [`let_and_return`]: Don't lint if a temporary borrow is involved + [#5680](https://github.com/rust-lang/rust-clippy/pull/5680) +* [`reversed_empty_ranges`]: Avoid linting `N..N` in for loop arguments in + [#5692](https://github.com/rust-lang/rust-clippy/pull/5692) +* [`if_same_then_else`]: Don't assume multiplication is always commutative + [#5702](https://github.com/rust-lang/rust-clippy/pull/5702) +* [`blacklisted_name`]: Remove `bar` from the default configuration + [#5712](https://github.com/rust-lang/rust-clippy/pull/5712) +* [`redundant_pattern_matching`]: Avoid suggesting non-`const fn` calls in const contexts + [#5724](https://github.com/rust-lang/rust-clippy/pull/5724) + +### Suggestion Fixes/Improvements + +* Fix suggestion of [`unit_arg`] lint, so that it suggest semantic equivalent code + [#4455](https://github.com/rust-lang/rust-clippy/pull/4455) +* Add auto applicable suggestion to [`macro_use_imports`] + [#5279](https://github.com/rust-lang/rust-clippy/pull/5279) + +### ICE Fixes + +* Fix ICE in the `consts` module of Clippy [#5709](https://github.com/rust-lang/rust-clippy/pull/5709) + +### Documentation Improvements + +* Improve code examples across multiple lints [#5664](https://github.com/rust-lang/rust-clippy/pull/5664) + +### Others + +* Introduce a `--rustc` flag to `clippy-driver`, which turns `clippy-driver` + into `rustc` and passes all the given arguments to `rustc`. This is especially + useful for tools that need the `rustc` version Clippy was compiled with, + instead of the Clippy version. E.g. `clippy-driver --rustc --version` will + print the output of `rustc --version`. + [#5178](https://github.com/rust-lang/rust-clippy/pull/5178) +* New issue templates now make it easier to complain if Clippy is too annoying + or not annoying enough! [#5735](https://github.com/rust-lang/rust-clippy/pull/5735) ## Rust 1.45 -Current beta, release 2020-07-16 +Current stable, released 2020-07-16 [891e1a8...7ea7cd1](https://github.com/rust-lang/rust-clippy/compare/891e1a8...7ea7cd1) @@ -87,7 +149,7 @@ and [`similar_names`]. [#5651](https://github.com/rust-lang/rust-clippy/pull/565 ## Rust 1.44 -Current stable, released 2020-06-04 +Released 2020-06-04 [204bb9b...891e1a8](https://github.com/rust-lang/rust-clippy/compare/204bb9b...891e1a8) From aba0d244d419261f94b3d942953412e35c3e857e Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 16 Jul 2020 15:40:13 +0200 Subject: [PATCH 18/36] Typo: Change Log -> Changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9d0a15b755..776b04295f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# Change Log +# Changelog All notable changes to this project will be documented in this file. See [Changelog Update](doc/changelog_update.md) if you want to update this From 62db617e401487f7b4b5d2d19591b16c7339d131 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 13 Jul 2020 16:45:35 +1000 Subject: [PATCH 19/36] Avoid storing `SymbolStr` in a struct. It's intended only for very temporary use. --- clippy_lints/src/non_expressive_names.rs | 13 +++++++------ clippy_lints/src/unsafe_removed_from_name.rs | 4 ++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 7128fee9bcf..1d4772bb3d6 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -8,7 +8,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::symbol::{Ident, SymbolStr}; +use rustc_span::symbol::{Ident, Symbol}; use std::cmp::Ordering; declare_clippy_lint! { @@ -75,7 +75,7 @@ pub struct NonExpressiveNames { impl_lint_pass!(NonExpressiveNames => [SIMILAR_NAMES, MANY_SINGLE_CHAR_NAMES, JUST_UNDERSCORES_AND_DIGITS]); struct ExistingName { - interned: SymbolStr, + interned: Symbol, span: Span, len: usize, exemptions: &'static [&'static str], @@ -218,18 +218,19 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { let mut split_at = None; match existing_name.len.cmp(&count) { Ordering::Greater => { - if existing_name.len - count != 1 || levenstein_not_1(&interned_name, &existing_name.interned) { + if existing_name.len - count != 1 || levenstein_not_1(&interned_name, &existing_name.interned.as_str()) { continue; } }, Ordering::Less => { - if count - existing_name.len != 1 || levenstein_not_1(&existing_name.interned, &interned_name) { + if count - existing_name.len != 1 || levenstein_not_1(&existing_name.interned.as_str(), &interned_name) { continue; } }, Ordering::Equal => { let mut interned_chars = interned_name.chars(); - let mut existing_chars = existing_name.interned.chars(); + let interned_str = existing_name.interned.as_str(); + let mut existing_chars = interned_str.chars(); let first_i = interned_chars.next().expect("we know we have at least one char"); let first_e = existing_chars.next().expect("we know we have at least one char"); let eq_or_numeric = |(a, b): (char, char)| a == b || a.is_numeric() && b.is_numeric(); @@ -302,7 +303,7 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { } self.0.names.push(ExistingName { exemptions: get_exemptions(&interned_name).unwrap_or(&[]), - interned: interned_name, + interned: ident.name, span: ident.span, len: count, }); diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs index 735800e7e74..154082a0fdb 100644 --- a/clippy_lints/src/unsafe_removed_from_name.rs +++ b/clippy_lints/src/unsafe_removed_from_name.rs @@ -3,7 +3,7 @@ use rustc_ast::ast::{Item, ItemKind, UseTree, UseTreeKind}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use rustc_span::symbol::{Ident, SymbolStr}; +use rustc_span::symbol::Ident; declare_clippy_lint! { /// **What it does:** Checks for imports that remove "unsafe" from an item's @@ -73,6 +73,6 @@ fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext<'_>, } #[must_use] -fn contains_unsafe(name: &SymbolStr) -> bool { +fn contains_unsafe(name: &str) -> bool { name.contains("Unsafe") || name.contains("unsafe") } From 70a41a92815a79c88dd9a2e8aa02503a3b95eae8 Mon Sep 17 00:00:00 2001 From: JarredAllen Date: Thu, 16 Jul 2020 16:51:12 -0700 Subject: [PATCH 20/36] Enable detecting multiple-argument panics --- clippy_lints/src/panic_unimplemented.rs | 9 ++-- tests/ui/panicking_macros.rs | 8 ++++ tests/ui/panicking_macros.stderr | 62 +++++++++++++++++++++++-- 3 files changed, 69 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 10f4694640e..9944b4096ba 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -96,23 +96,20 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { if_chain! { if let ExprKind::Block(ref block, _) = expr.kind; if let Some(ref ex) = block.expr; - if let Some(params) = match_function_call(cx, ex, &paths::BEGIN_PANIC); - if params.len() == 1; + if let Some(params) = match_function_call(cx, ex, &paths::BEGIN_PANIC) + .or(match_function_call(cx, ex, &paths::BEGIN_PANIC_FMT)); then { + let span = get_outer_span(expr); if is_expn_of(expr.span, "unimplemented").is_some() { - let span = get_outer_span(expr); span_lint(cx, UNIMPLEMENTED, span, "`unimplemented` should not be present in production code"); } else if is_expn_of(expr.span, "todo").is_some() { - let span = get_outer_span(expr); span_lint(cx, TODO, span, "`todo` should not be present in production code"); } else if is_expn_of(expr.span, "unreachable").is_some() { - let span = get_outer_span(expr); span_lint(cx, UNREACHABLE, span, "`unreachable` should not be present in production code"); } else if is_expn_of(expr.span, "panic").is_some() { - let span = get_outer_span(expr); span_lint(cx, PANIC, span, "`panic` should not be present in production code"); match_panic(params, expr, cx); diff --git a/tests/ui/panicking_macros.rs b/tests/ui/panicking_macros.rs index dabb695368d..f91ccfaed74 100644 --- a/tests/ui/panicking_macros.rs +++ b/tests/ui/panicking_macros.rs @@ -4,24 +4,32 @@ fn panic() { let a = 2; panic!(); + panic!("message"); + panic!("{} {}", "panic with", "multiple arguments"); let b = a + 2; } fn todo() { let a = 2; todo!(); + todo!("message"); + todo!("{} {}", "panic with", "multiple arguments"); let b = a + 2; } fn unimplemented() { let a = 2; unimplemented!(); + unimplemented!("message"); + unimplemented!("{} {}", "panic with", "multiple arguments"); let b = a + 2; } fn unreachable() { let a = 2; unreachable!(); + unreachable!("message"); + unreachable!("{} {}", "panic with", "multiple arguments"); let b = a + 2; } diff --git a/tests/ui/panicking_macros.stderr b/tests/ui/panicking_macros.stderr index 72319bc7e45..37c11d72a57 100644 --- a/tests/ui/panicking_macros.stderr +++ b/tests/ui/panicking_macros.stderr @@ -6,29 +6,83 @@ LL | panic!(); | = note: `-D clippy::panic` implied by `-D warnings` +error: `panic` should not be present in production code + --> $DIR/panicking_macros.rs:7:5 + | +LL | panic!("message"); + | ^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `panic` should not be present in production code + --> $DIR/panicking_macros.rs:8:5 + | +LL | panic!("{} {}", "panic with", "multiple arguments"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + error: `todo` should not be present in production code - --> $DIR/panicking_macros.rs:12:5 + --> $DIR/panicking_macros.rs:14:5 | LL | todo!(); | ^^^^^^^^ | = note: `-D clippy::todo` implied by `-D warnings` +error: `todo` should not be present in production code + --> $DIR/panicking_macros.rs:15:5 + | +LL | todo!("message"); + | ^^^^^^^^^^^^^^^^^ + +error: `todo` should not be present in production code + --> $DIR/panicking_macros.rs:16:5 + | +LL | todo!("{} {}", "panic with", "multiple arguments"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: `unimplemented` should not be present in production code - --> $DIR/panicking_macros.rs:18:5 + --> $DIR/panicking_macros.rs:22:5 | LL | unimplemented!(); | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unimplemented` implied by `-D warnings` -error: `unreachable` should not be present in production code +error: `unimplemented` should not be present in production code + --> $DIR/panicking_macros.rs:23:5 + | +LL | unimplemented!("message"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `unimplemented` should not be present in production code --> $DIR/panicking_macros.rs:24:5 | +LL | unimplemented!("{} {}", "panic with", "multiple arguments"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `unreachable` should not be present in production code + --> $DIR/panicking_macros.rs:30:5 + | LL | unreachable!(); | ^^^^^^^^^^^^^^^ | = note: `-D clippy::unreachable` implied by `-D warnings` -error: aborting due to 4 previous errors +error: `unreachable` should not be present in production code + --> $DIR/panicking_macros.rs:31:5 + | +LL | unreachable!("message"); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `unreachable` should not be present in production code + --> $DIR/panicking_macros.rs:32:5 + | +LL | unreachable!("{} {}", "panic with", "multiple arguments"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors From 07867fde592babd74ee9934726c4c7010dee149b Mon Sep 17 00:00:00 2001 From: JarredAllen Date: Thu, 16 Jul 2020 16:58:21 -0700 Subject: [PATCH 21/36] Clean up dogfood fallout --- clippy_lints/src/panic_unimplemented.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 9944b4096ba..6379dffd22e 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -97,7 +97,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { if let ExprKind::Block(ref block, _) = expr.kind; if let Some(ref ex) = block.expr; if let Some(params) = match_function_call(cx, ex, &paths::BEGIN_PANIC) - .or(match_function_call(cx, ex, &paths::BEGIN_PANIC_FMT)); + .or_else(|| match_function_call(cx, ex, &paths::BEGIN_PANIC_FMT)); then { let span = get_outer_span(expr); if is_expn_of(expr.span, "unimplemented").is_some() { From 3618b97f59d9696c3e5ef83948269d0d7abfdc5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 17 Jul 2020 01:58:41 +0200 Subject: [PATCH 22/36] fix typos (found by codespell) --- clippy_lints/src/deprecated_lints.rs | 2 +- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/inherent_impl.rs | 2 +- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/missing_const_for_fn.rs | 2 +- clippy_lints/src/modulo_arithmetic.rs | 2 +- clippy_lints/src/option_if_let_else.rs | 2 +- clippy_lints/src/utils/numeric_literal.rs | 2 +- tests/ui/manual_async_fn.fixed | 2 +- tests/ui/manual_async_fn.rs | 2 +- tests/ui/manual_async_fn.stderr | 2 +- tests/ui/never_loop.rs | 2 +- tests/ui/precedence.fixed | 2 +- tests/ui/precedence.rs | 2 +- tests/ui/vec_resize_to_zero.rs | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index 818d8188a78..c17a0e83330 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -153,7 +153,7 @@ declare_deprecated_lint! { /// /// **Deprecation reason:** Associated-constants are now preferred. pub REPLACE_CONSTS, - "associated-constants `MIN`/`MAX` of integers are prefered to `{min,max}_value()` and module constants" + "associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants" } declare_deprecated_lint! { diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 323cad7fa1a..7a3f35aca0a 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -10,7 +10,7 @@ use rustc_span::source_map::Span; declare_clippy_lint! { /// **What it does:** Checks for explicit `deref()` or `deref_mut()` method calls. /// - /// **Why is this bad?** Derefencing 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:** diff --git a/clippy_lints/src/inherent_impl.rs b/clippy_lints/src/inherent_impl.rs index bd7ca038839..9fb10c7f627 100644 --- a/clippy_lints/src/inherent_impl.rs +++ b/clippy_lints/src/inherent_impl.rs @@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { .. } = item.kind { - // Remember for each inherent implementation encoutered its span and generics + // Remember for each inherent implementation encountered its span and generics // but filter out implementations that have generic params (type or lifetime) // or are derived from a macro if !in_macro(item.span) && generics.params.is_empty() { diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 7a4ca3902b3..823afdfd289 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -463,7 +463,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ); store.register_removed( "clippy::replace_consts", - "associated-constants `MIN`/`MAX` of integers are prefered to `{min,max}_value()` and module constants", + "associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants", ); store.register_removed( "clippy::regex_macro", diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index bdce1bf1521..1ad184dfc46 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -131,7 +131,7 @@ 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_dropable(cx: &LateContext<'_>, param_tys: &[hir::Ty<'_>]) -> bool { - // If any of the params are dropable, return true + // 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) diff --git a/clippy_lints/src/modulo_arithmetic.rs b/clippy_lints/src/modulo_arithmetic.rs index 59ccc6333fd..5041af750ce 100644 --- a/clippy_lints/src/modulo_arithmetic.rs +++ b/clippy_lints/src/modulo_arithmetic.rs @@ -8,7 +8,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use std::fmt::Display; declare_clippy_lint! { - /// **What it does:** Checks for modulo arithemtic. + /// **What it does:** Checks for modulo arithmetic. /// /// **Why is this bad?** The results of modulo (%) operation might differ /// depending on the language, when negative numbers are involved. diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 8dbe58763bf..9922d906118 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 occurences of the +/// A struct containing information about occurrences of the /// `if let Some(..) = .. else` construct that this lint detects. struct OptionIfLetElseOccurence { option: String, diff --git a/clippy_lints/src/utils/numeric_literal.rs b/clippy_lints/src/utils/numeric_literal.rs index 87cb454f654..5e8800d38eb 100644 --- a/clippy_lints/src/utils/numeric_literal.rs +++ b/clippy_lints/src/utils/numeric_literal.rs @@ -36,7 +36,7 @@ pub struct NumericLiteral<'a> { pub integer: &'a str, /// The fraction part of the number. pub fraction: Option<&'a str>, - /// The character used as exponent seperator (b'e' or b'E') and the exponent part. + /// The character used as exponent separator (b'e' or b'E') and the exponent part. pub exponent: Option<(char, &'a str)>, /// The type suffix, including preceding underscore if present. diff --git a/tests/ui/manual_async_fn.fixed b/tests/ui/manual_async_fn.fixed index 6bb1032a172..27222cc0869 100644 --- a/tests/ui/manual_async_fn.fixed +++ b/tests/ui/manual_async_fn.fixed @@ -30,7 +30,7 @@ async fn already_async() -> impl Future { struct S {} impl S { async fn inh_fut() -> i32 { - // NOTE: this code is here just to check that the identation is correct in the suggested fix + // NOTE: this code is here just to check that the indentation is correct in the suggested fix let a = 42; let b = 21; if a < b { diff --git a/tests/ui/manual_async_fn.rs b/tests/ui/manual_async_fn.rs index d50c919188b..6a0f1b26c88 100644 --- a/tests/ui/manual_async_fn.rs +++ b/tests/ui/manual_async_fn.rs @@ -37,7 +37,7 @@ struct S {} impl S { fn inh_fut() -> impl Future { async { - // NOTE: this code is here just to check that the identation is correct in the suggested fix + // NOTE: this code is here just to check that the indentation is correct in the suggested fix let a = 42; let b = 21; if a < b { diff --git a/tests/ui/manual_async_fn.stderr b/tests/ui/manual_async_fn.stderr index f278ee41aa3..a1904c904d0 100644 --- a/tests/ui/manual_async_fn.stderr +++ b/tests/ui/manual_async_fn.stderr @@ -57,7 +57,7 @@ LL | async fn inh_fut() -> i32 { help: move the body of the async block to the enclosing function | LL | fn inh_fut() -> impl Future { -LL | // NOTE: this code is here just to check that the identation is correct in the suggested fix +LL | // NOTE: this code is here just to check that the indentation is correct in the suggested fix LL | let a = 42; LL | let b = 21; LL | if a < b { diff --git a/tests/ui/never_loop.rs b/tests/ui/never_loop.rs index cbc4ca39161..2770eb2b2ab 100644 --- a/tests/ui/never_loop.rs +++ b/tests/ui/never_loop.rs @@ -166,7 +166,7 @@ pub fn test14() { } } -// Issue #1991: the outter loop should not warn. +// Issue #1991: the outer loop should not warn. pub fn test15() { 'label: loop { while false { diff --git a/tests/ui/precedence.fixed b/tests/ui/precedence.fixed index 17b1f1bd0bf..4d284ae1319 100644 --- a/tests/ui/precedence.fixed +++ b/tests/ui/precedence.fixed @@ -32,7 +32,7 @@ fn main() { let _ = -(1i32.abs()); let _ = -(1f32.abs()); - // Odd functions shoud not trigger an error + // Odd functions should not trigger an error let _ = -1f64.asin(); let _ = -1f64.asinh(); let _ = -1f64.atan(); diff --git a/tests/ui/precedence.rs b/tests/ui/precedence.rs index 2d0891fd3c2..2d08e82f349 100644 --- a/tests/ui/precedence.rs +++ b/tests/ui/precedence.rs @@ -32,7 +32,7 @@ fn main() { let _ = -(1i32.abs()); let _ = -(1f32.abs()); - // Odd functions shoud not trigger an error + // Odd functions should not trigger an error let _ = -1f64.asin(); let _ = -1f64.asinh(); let _ = -1f64.atan(); diff --git a/tests/ui/vec_resize_to_zero.rs b/tests/ui/vec_resize_to_zero.rs index 0263e2f5f20..7ed27439ec6 100644 --- a/tests/ui/vec_resize_to_zero.rs +++ b/tests/ui/vec_resize_to_zero.rs @@ -7,7 +7,7 @@ fn main() { // not applicable vec![1, 2, 3, 4, 5].resize(2, 5); - // applicable here, but only implemented for integer litterals for now + // applicable here, but only implemented for integer literals for now vec!["foo", "bar", "baz"].resize(0, "bar"); // not applicable From 5a20489c5ca0951827cbb1b4d72ddfdfd393713a Mon Sep 17 00:00:00 2001 From: Valentin Lazureanu Date: Fri, 17 Jul 2020 08:47:04 +0000 Subject: [PATCH 23/36] Rename TypeckTables to TypeckResults. --- clippy_lints/src/arithmetic.rs | 6 +- clippy_lints/src/assertions_on_constants.rs | 4 +- clippy_lints/src/assign_ops.rs | 6 +- clippy_lints/src/atomic_ordering.rs | 2 +- clippy_lints/src/attrs.rs | 23 ++-- clippy_lints/src/await_holding_lock.rs | 4 +- clippy_lints/src/bit_mask.rs | 2 +- clippy_lints/src/booleans.rs | 14 ++- clippy_lints/src/bytecount.rs | 4 +- clippy_lints/src/cognitive_complexity.rs | 2 +- clippy_lints/src/comparison_chain.rs | 2 +- clippy_lints/src/consts.rs | 78 ++++++------ clippy_lints/src/copies.rs | 2 +- clippy_lints/src/default_trait_access.rs | 2 +- clippy_lints/src/dereference.rs | 4 +- clippy_lints/src/drop_forget_ref.rs | 2 +- clippy_lints/src/duration_subsec.rs | 4 +- clippy_lints/src/entry.rs | 2 +- clippy_lints/src/eq_op.rs | 16 +-- clippy_lints/src/erasing_op.rs | 2 +- clippy_lints/src/escape.rs | 2 +- clippy_lints/src/eta_reduction.rs | 6 +- clippy_lints/src/eval_order_dependence.rs | 4 +- clippy_lints/src/fallible_impl_from.rs | 6 +- clippy_lints/src/float_literal.rs | 2 +- clippy_lints/src/floating_point_arithmetic.rs | 37 +++--- clippy_lints/src/format.rs | 2 +- clippy_lints/src/functions.rs | 23 ++-- clippy_lints/src/get_last_with_len.rs | 2 +- clippy_lints/src/identity_op.rs | 8 +- clippy_lints/src/if_let_mutex.rs | 2 +- clippy_lints/src/if_let_some_result.rs | 2 +- clippy_lints/src/implicit_saturating_sub.rs | 4 +- clippy_lints/src/indexing_slicing.rs | 12 +- clippy_lints/src/infinite_iter.rs | 4 +- clippy_lints/src/integer_division.rs | 2 +- clippy_lints/src/large_stack_arrays.rs | 2 +- clippy_lints/src/len_zero.rs | 2 +- clippy_lints/src/let_if_seq.rs | 2 +- clippy_lints/src/let_underscore.rs | 4 +- clippy_lints/src/loops.rs | 44 ++++--- clippy_lints/src/map_clone.rs | 6 +- clippy_lints/src/map_identity.rs | 4 +- clippy_lints/src/map_unit_fn.rs | 19 +-- clippy_lints/src/match_on_vec_items.rs | 4 +- clippy_lints/src/matches.rs | 28 ++--- clippy_lints/src/mem_discriminant.rs | 2 +- clippy_lints/src/mem_forget.rs | 2 +- clippy_lints/src/mem_replace.rs | 4 +- .../src/methods/bind_instead_of_map.rs | 2 +- .../src/methods/inefficient_to_string.rs | 4 +- .../methods/manual_saturating_arithmetic.rs | 4 +- clippy_lints/src/methods/mod.rs | 114 +++++++++--------- .../src/methods/option_map_unwrap_or.rs | 4 +- clippy_lints/src/minmax.rs | 10 +- clippy_lints/src/misc.rs | 16 +-- clippy_lints/src/modulo_arithmetic.rs | 6 +- clippy_lints/src/mut_key.rs | 2 +- clippy_lints/src/mut_mut.rs | 2 +- clippy_lints/src/mut_reference.rs | 6 +- clippy_lints/src/mutable_debug_assertion.rs | 2 +- clippy_lints/src/mutex_atomic.rs | 2 +- clippy_lints/src/needless_bool.rs | 5 +- clippy_lints/src/needless_borrow.rs | 6 +- clippy_lints/src/needless_pass_by_value.rs | 3 +- clippy_lints/src/needless_update.rs | 2 +- clippy_lints/src/neg_cmp_op_on_partial_ord.rs | 2 +- clippy_lints/src/neg_multiply.rs | 4 +- clippy_lints/src/no_effect.rs | 11 +- clippy_lints/src/non_copy_const.rs | 6 +- clippy_lints/src/open_options.rs | 4 +- clippy_lints/src/option_if_let_else.rs | 3 +- .../src/overflow_check_conditional.rs | 8 +- clippy_lints/src/path_buf_push_overwrite.rs | 2 +- clippy_lints/src/pattern_type_mismatch.rs | 6 +- clippy_lints/src/ptr_offset_with_cast.rs | 4 +- clippy_lints/src/question_mark.rs | 4 +- clippy_lints/src/ranges.rs | 6 +- clippy_lints/src/regex.rs | 2 +- clippy_lints/src/repeat_once.rs | 4 +- clippy_lints/src/shadow.rs | 2 +- clippy_lints/src/strings.rs | 2 +- clippy_lints/src/swap.rs | 2 +- clippy_lints/src/to_digit_is_some.rs | 2 +- clippy_lints/src/transmute.rs | 4 +- clippy_lints/src/transmuting_null.rs | 2 +- clippy_lints/src/try_err.rs | 4 +- clippy_lints/src/types.rs | 46 +++---- clippy_lints/src/unnamed_address.rs | 10 +- clippy_lints/src/unnecessary_sort_by.rs | 2 +- clippy_lints/src/unwrap.rs | 2 +- clippy_lints/src/useless_conversion.rs | 16 +-- clippy_lints/src/utils/higher.rs | 2 +- clippy_lints/src/utils/hir_utils.rs | 46 +++---- clippy_lints/src/utils/inspector.rs | 10 +- clippy_lints/src/utils/internal_lints.rs | 4 +- clippy_lints/src/utils/mod.rs | 20 ++- clippy_lints/src/utils/usage.rs | 9 +- clippy_lints/src/vec.rs | 6 +- clippy_lints/src/vec_resize_to_zero.rs | 2 +- clippy_lints/src/verbose_file_reads.rs | 4 +- clippy_lints/src/zero_div_zero.rs | 4 +- doc/common_tools_writing_lints.md | 16 +-- 103 files changed, 471 insertions(+), 424 deletions(-) diff --git a/clippy_lints/src/arithmetic.rs b/clippy_lints/src/arithmetic.rs index da60856fac9..e84481f9b53 100644 --- a/clippy_lints/src/arithmetic.rs +++ b/clippy_lints/src/arithmetic.rs @@ -86,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for Arithmetic { _ => (), } - let (l_ty, r_ty) = (cx.tables().expr_ty(l), cx.tables().expr_ty(r)); + let (l_ty, r_ty) = (cx.typeck_results().expr_ty(l), cx.typeck_results().expr_ty(r)); if l_ty.peel_refs().is_integral() && r_ty.peel_refs().is_integral() { span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); self.expr_span = Some(expr.span); @@ -96,8 +96,8 @@ impl<'tcx> LateLintPass<'tcx> for Arithmetic { } }, hir::ExprKind::Unary(hir::UnOp::UnNeg, arg) => { - let ty = cx.tables().expr_ty(arg); - if constant_simple(cx, cx.tables(), expr).is_none() { + let ty = cx.typeck_results().expr_ty(arg); + if constant_simple(cx, cx.typeck_results(), expr).is_none() { if ty.is_integral() { span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); self.expr_span = Some(expr.span); diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index cffe8d94e27..982d5ecf8d0 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { } if_chain! { if let ExprKind::Unary(_, ref lit) = e.kind; - if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.tables(), lit); + if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), lit); if is_true; then { lint_true(true); @@ -121,7 +121,7 @@ fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) if let ExprKind::DropTemps(ref expr) = expr.kind; if let ExprKind::Unary(UnOp::UnNot, ref expr) = expr.kind; // bind the first argument of the `assert!` macro - if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.tables(), expr); + if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), expr); // arm 1 pattern if let PatKind::Lit(ref lit_expr) = arms[0].pat.kind; if let ExprKind::Lit(ref lit) = lit_expr.kind; diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs index bc6e868823f..dab1e96e282 100644 --- a/clippy_lints/src/assign_ops.rs +++ b/clippy_lints/src/assign_ops.rs @@ -82,8 +82,8 @@ impl<'tcx> LateLintPass<'tcx> for AssignOps { hir::ExprKind::Assign(assignee, e, _) => { if let hir::ExprKind::Binary(op, l, r) = &e.kind { let lint = |assignee: &hir::Expr<'_>, rhs: &hir::Expr<'_>| { - let ty = cx.tables().expr_ty(assignee); - let rty = cx.tables().expr_ty(rhs); + let ty = cx.typeck_results().expr_ty(assignee); + let rty = cx.typeck_results().expr_ty(rhs); macro_rules! ops { ($op:expr, $cx:expr, @@ -167,7 +167,7 @@ impl<'tcx> LateLintPass<'tcx> for AssignOps { // a = b commutative_op a // Limited to primitive type as these ops are know to be commutative if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r) - && cx.tables().expr_ty(assignee).is_primitive_ty() + && cx.typeck_results().expr_ty(assignee).is_primitive_ty() { match op.node { hir::BinOpKind::Add diff --git a/clippy_lints/src/atomic_ordering.rs b/clippy_lints/src/atomic_ordering.rs index efd3f0f671c..277fe350055 100644 --- a/clippy_lints/src/atomic_ordering.rs +++ b/clippy_lints/src/atomic_ordering.rs @@ -53,7 +53,7 @@ const ATOMIC_TYPES: [&str; 12] = [ ]; fn type_is_atomic(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - if let ty::Adt(&ty::AdtDef { did, .. }, _) = cx.tables().expr_ty(expr).kind { + if let ty::Adt(&ty::AdtDef { did, .. }, _) = cx.typeck_results().expr_ty(expr).kind { ATOMIC_TYPES .iter() .any(|ty| match_def_path(cx, did, &["core", "sync", "atomic", ty])) diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index c29432bf933..27a7fa88622 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -461,7 +461,7 @@ fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMet fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool { if let ItemKind::Fn(_, _, eid) = item.kind { - is_relevant_expr(cx, cx.tcx.body_tables(eid), &cx.tcx.hir().body(eid).value) + is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value) } else { true } @@ -469,7 +469,7 @@ fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool { fn is_relevant_impl(cx: &LateContext<'_>, item: &ImplItem<'_>) -> bool { match item.kind { - ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.body_tables(eid), &cx.tcx.hir().body(eid).value), + ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value), _ => false, } } @@ -478,31 +478,34 @@ fn is_relevant_trait(cx: &LateContext<'_>, item: &TraitItem<'_>) -> bool { match item.kind { TraitItemKind::Fn(_, TraitFn::Required(_)) => true, TraitItemKind::Fn(_, TraitFn::Provided(eid)) => { - is_relevant_expr(cx, cx.tcx.body_tables(eid), &cx.tcx.hir().body(eid).value) + is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value) }, _ => false, } } -fn is_relevant_block(cx: &LateContext<'_>, tables: &ty::TypeckTables<'_>, block: &Block<'_>) -> bool { +fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, block: &Block<'_>) -> bool { block.stmts.first().map_or( - block.expr.as_ref().map_or(false, |e| is_relevant_expr(cx, tables, e)), + block + .expr + .as_ref() + .map_or(false, |e| is_relevant_expr(cx, typeck_results, e)), |stmt| match &stmt.kind { StmtKind::Local(_) => true, - StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, tables, expr), + StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, typeck_results, expr), _ => false, }, ) } -fn is_relevant_expr(cx: &LateContext<'_>, tables: &ty::TypeckTables<'_>, expr: &Expr<'_>) -> bool { +fn is_relevant_expr(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, expr: &Expr<'_>) -> bool { match &expr.kind { - ExprKind::Block(block, _) => is_relevant_block(cx, tables, block), - ExprKind::Ret(Some(e)) => is_relevant_expr(cx, tables, e), + 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 { - tables + typeck_results .qpath_res(qpath, path_expr.hir_id) .opt_def_id() .map_or(true, |fun_id| !match_def_path(cx, fun_id, &paths::BEGIN_PANIC)) diff --git a/clippy_lints/src/await_holding_lock.rs b/clippy_lints/src/await_holding_lock.rs index d337262dfa6..b10b1e0a65a 100644 --- a/clippy_lints/src/await_holding_lock.rs +++ b/clippy_lints/src/await_holding_lock.rs @@ -59,8 +59,8 @@ impl LateLintPass<'_> for AwaitHoldingLock { hir_id: body.value.hir_id, }; let def_id = cx.tcx.hir().body_owner_def_id(body_id); - let tables = cx.tcx.typeck_tables_of(def_id); - check_interior_types(cx, &tables.generator_interior_types, body.value.span); + let typeck_results = cx.tcx.typeck(def_id); + check_interior_types(cx, &typeck_results.generator_interior_types, body.value.span); } } } diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index d1d177e7a4a..81a34021e8a 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -319,7 +319,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.tables(), lit)?.0 { + match constant(cx, cx.typeck_results(), lit)?.0 { Constant::Int(n) => Some(n), _ => None, } diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 32d0979e99b..18529f2113e 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -111,8 +111,12 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { match &e.kind { ExprKind::Unary(UnOp::UnNot, inner) => return Ok(Bool::Not(box self.run(inner)?)), ExprKind::Binary(binop, lhs, rhs) => match &binop.node { - BinOpKind::Or => return Ok(Bool::Or(self.extract(BinOpKind::Or, &[lhs, rhs], Vec::new())?)), - BinOpKind::And => return Ok(Bool::And(self.extract(BinOpKind::And, &[lhs, rhs], Vec::new())?)), + BinOpKind::Or => { + return Ok(Bool::Or(self.extract(BinOpKind::Or, &[lhs, rhs], Vec::new())?)); + }, + BinOpKind::And => { + return Ok(Bool::And(self.extract(BinOpKind::And, &[lhs, rhs], Vec::new())?)); + }, _ => (), }, ExprKind::Lit(lit) => match lit.node { @@ -248,7 +252,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { }) }, ExprKind::MethodCall(path, _, args, _) if args.len() == 1 => { - let type_of_receiver = cx.tables().expr_ty(&args[0]); + 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)) { @@ -450,7 +454,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { self.bool_expr(e) }, ExprKind::Unary(UnOp::UnNot, inner) => { - if self.cx.tables().node_types()[inner.hir_id].is_bool() { + if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() { self.bool_expr(e); } else { walk_expr(self, e); @@ -465,7 +469,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { } fn implements_ord<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool { - let ty = cx.tables().expr_ty(expr); + let ty = cx.typeck_results().expr_ty(expr); get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[])) } diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index 1cdfea1f526..dde799fcae4 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -53,7 +53,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.tables().expr_ty(&filter_args[0])), + walk_ptrs_ty(cx.typeck_results().expr_ty(&filter_args[0])), &paths::SLICE_ITER); then { let needle = match get_path_name(l) { @@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount { _ => { return; } } }; - if ty::Uint(UintTy::U8) != walk_ptrs_ty(cx.tables().expr_ty(needle)).kind { + if ty::Uint(UintTy::U8) != walk_ptrs_ty(cx.typeck_results().expr_ty(needle)).kind { return; } let haystack = if let ExprKind::MethodCall(ref path, _, ref args, _) = diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 6bbdbe957cc..14ef8c319ef 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -60,7 +60,7 @@ impl CognitiveComplexity { let mut helper = CCHelper { cc: 1, returns: 0 }; helper.visit_expr(expr); let CCHelper { cc, returns } = helper; - let ret_ty = cx.tables().node_type(expr.hir_id); + 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)) { returns } else { diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs index 25ccabc1c88..99f161a0510 100644 --- a/clippy_lints/src/comparison_chain.rs +++ b/clippy_lints/src/comparison_chain.rs @@ -99,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain { } // Check that the type being compared implements `core::cmp::Ord` - let ty = cx.tables().expr_ty(lhs1); + 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, &[])); if !is_ord { diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index e6ef54f528f..49ff86a205d 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -174,12 +174,12 @@ pub fn lit_to_constant(lit: &LitKind, ty: Option>) -> Constant { pub fn constant<'tcx>( lcx: &LateContext<'tcx>, - tables: &ty::TypeckTables<'tcx>, + typeck_results: &ty::TypeckResults<'tcx>, e: &Expr<'_>, ) -> Option<(Constant, bool)> { let mut cx = ConstEvalLateContext { lcx, - tables, + typeck_results, param_env: lcx.param_env, needed_resolution: false, substs: lcx.tcx.intern_substs(&[]), @@ -189,20 +189,20 @@ pub fn constant<'tcx>( pub fn constant_simple<'tcx>( lcx: &LateContext<'tcx>, - tables: &ty::TypeckTables<'tcx>, + typeck_results: &ty::TypeckResults<'tcx>, e: &Expr<'_>, ) -> Option { - constant(lcx, tables, e).and_then(|(cst, res)| if res { None } else { Some(cst) }) + constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) }) } -/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckTables`. +/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`. pub fn constant_context<'a, 'tcx>( lcx: &'a LateContext<'tcx>, - tables: &'a ty::TypeckTables<'tcx>, + typeck_results: &'a ty::TypeckResults<'tcx>, ) -> ConstEvalLateContext<'a, 'tcx> { ConstEvalLateContext { lcx, - tables, + typeck_results, param_env: lcx.param_env, needed_resolution: false, substs: lcx.tcx.intern_substs(&[]), @@ -211,7 +211,7 @@ pub fn constant_context<'a, 'tcx>( pub struct ConstEvalLateContext<'a, 'tcx> { lcx: &'a LateContext<'tcx>, - tables: &'a ty::TypeckTables<'tcx>, + typeck_results: &'a ty::TypeckResults<'tcx>, param_env: ty::ParamEnv<'tcx>, needed_resolution: bool, substs: SubstsRef<'tcx>, @@ -224,21 +224,21 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { return self.ifthenelse(cond, then, otherwise); } match e.kind { - ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.tables.expr_ty(e)), + ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)), ExprKind::Block(ref block, _) => self.block(block), - ExprKind::Lit(ref lit) => Some(lit_to_constant(&lit.node, self.tables.expr_ty_opt(e))), + ExprKind::Lit(ref lit) => Some(lit_to_constant(&lit.node, self.typeck_results.expr_ty_opt(e))), ExprKind::Array(ref vec) => self.multi(vec).map(Constant::Vec), ExprKind::Tup(ref tup) => self.multi(tup).map(Constant::Tuple), ExprKind::Repeat(ref value, _) => { - let n = match self.tables.expr_ty(e).kind { + let n = match self.typeck_results.expr_ty(e).kind { ty::Array(_, n) => n.try_eval_usize(self.lcx.tcx, self.lcx.param_env)?, _ => span_bug!(e.span, "typeck error"), }; self.expr(value).map(|v| Constant::Repeat(Box::new(v), n)) }, ExprKind::Unary(op, ref operand) => self.expr(operand).and_then(|o| match op { - UnOp::UnNot => self.constant_not(&o, self.tables.expr_ty(e)), - UnOp::UnNeg => self.constant_negate(&o, self.tables.expr_ty(e)), + UnOp::UnNot => self.constant_not(&o, self.typeck_results.expr_ty(e)), + UnOp::UnNeg => self.constant_negate(&o, self.typeck_results.expr_ty(e)), UnOp::UnDeref => Some(o), }), ExprKind::Binary(op, ref left, ref right) => self.binop(op, left, right), @@ -247,7 +247,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { if_chain! { if args.is_empty(); if let ExprKind::Path(qpath) = &callee.kind; - let res = self.tables.qpath_res(qpath, callee.hir_id); + let res = self.typeck_results.qpath_res(qpath, callee.hir_id); if let Some(def_id) = res.opt_def_id(); let def_path: Vec<_> = self.lcx.get_def_path(def_id).into_iter().map(Symbol::as_str).collect(); let def_path: Vec<&str> = def_path.iter().take(4).map(|s| &**s).collect(); @@ -319,10 +319,10 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { /// Lookup a possibly constant expression from a `ExprKind::Path`. fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option { - let res = self.tables.qpath_res(qpath, id); + let res = self.typeck_results.qpath_res(qpath, id); match res { Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => { - let substs = self.tables.node_substs(id); + let substs = self.typeck_results.node_substs(id); let substs = if self.substs.is_empty() { substs } else { @@ -332,7 +332,13 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { let result = self .lcx .tcx - .const_eval_resolve(self.param_env, ty::WithOptConstParam::unknown(def_id), substs, None, None) + .const_eval_resolve( + self.param_env, + ty::WithOptConstParam::unknown(def_id), + substs, + None, + None, + ) .ok() .map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?; let result = miri_to_const(&result); @@ -396,7 +402,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { let l = self.expr(left)?; let r = self.expr(right); match (l, r) { - (Constant::Int(l), Some(Constant::Int(r))) => match self.tables.expr_ty_opt(left)?.kind { + (Constant::Int(l), Some(Constant::Int(r))) => match self.typeck_results.expr_ty_opt(left)?.kind { ty::Int(ity) => { let l = sext(self.lcx.tcx, l, ity); let r = sext(self.lcx.tcx, r, ity); @@ -488,23 +494,25 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { pub fn miri_to_const(result: &ty::Const<'_>) -> Option { use rustc_middle::mir::interpret::{ConstValue, Scalar}; match result.val { - ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data: d, .. })) => match result.ty.kind { - ty::Bool => Some(Constant::Bool(d == 1)), - ty::Uint(_) | ty::Int(_) => Some(Constant::Int(d)), - ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits( - d.try_into().expect("invalid f32 bit representation"), - ))), - ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits( - d.try_into().expect("invalid f64 bit representation"), - ))), - ty::RawPtr(type_and_mut) => { - if let ty::Uint(_) = type_and_mut.ty.kind { - return Some(Constant::RawPtr(d)); - } - None - }, - // FIXME: implement other conversions. - _ => None, + ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data: d, .. })) => { + match result.ty.kind { + ty::Bool => Some(Constant::Bool(d == 1)), + ty::Uint(_) | ty::Int(_) => Some(Constant::Int(d)), + ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits( + d.try_into().expect("invalid f32 bit representation"), + ))), + ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits( + d.try_into().expect("invalid f64 bit representation"), + ))), + ty::RawPtr(type_and_mut) => { + if let ty::Uint(_) = type_and_mut.ty.kind { + return Some(Constant::RawPtr(d)); + } + None + }, + // FIXME: implement other conversions. + _ => None, + } }, ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty.kind { ty::Ref(_, tam, _) => match tam.kind { diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 1257032337a..1f8bff8d71e 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -320,7 +320,7 @@ fn bindings<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>) -> FxHashMap { if let Entry::Vacant(v) = map.entry(ident.name) { - v.insert(cx.tables().pat_ty(pat)); + v.insert(cx.typeck_results().pat_ty(pat)); } if let Some(ref as_pat) = *as_pat { bindings_impl(cx, as_pat, map); diff --git a/clippy_lints/src/default_trait_access.rs b/clippy_lints/src/default_trait_access.rs index fab95db0196..ea244768129 100644 --- a/clippy_lints/src/default_trait_access.rs +++ b/clippy_lints/src/default_trait_access.rs @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultTraitAccess { // 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 expr_ty = cx.tables().expr_ty(expr); + let expr_ty = cx.typeck_results().expr_ty(expr); if let ty::Adt(..) = expr_ty.kind { let replacement = format!("{}::default()", expr_ty); span_lint_and_sugg( diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 323cad7fa1a..102cf597d22 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -74,7 +74,7 @@ fn lint_deref(cx: &LateContext<'_>, method_name: &str, call_expr: &Expr<'_>, var match method_name { "deref" => { let impls_deref_trait = cx.tcx.lang_items().deref_trait().map_or(false, |id| { - implements_trait(cx, cx.tables().expr_ty(&call_expr), id, &[]) + implements_trait(cx, cx.typeck_results().expr_ty(&call_expr), id, &[]) }); if impls_deref_trait { span_lint_and_sugg( @@ -90,7 +90,7 @@ fn lint_deref(cx: &LateContext<'_>, method_name: &str, call_expr: &Expr<'_>, var }, "deref_mut" => { let impls_deref_mut_trait = cx.tcx.lang_items().deref_mut_trait().map_or(false, |id| { - implements_trait(cx, cx.tables().expr_ty(&call_expr), id, &[]) + implements_trait(cx, cx.typeck_results().expr_ty(&call_expr), id, &[]) }); if impls_deref_mut_trait { span_lint_and_sugg( diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index dcf772572e8..57ff569f14b 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { let lint; let msg; let arg = &args[0]; - let arg_ty = cx.tables().expr_ty(arg); + let arg_ty = cx.typeck_results().expr_ty(arg); if let ty::Ref(..) = arg_ty.kind { if match_def_path(cx, def_id, &paths::DROP) { diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index 2ded375091c..1dfb2eaa579 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -43,8 +43,8 @@ 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.tables().expr_ty(&args[0])), &paths::DURATION); - if let Some((Constant::Int(divisor), _)) = constant(cx, cx.tables(), right); + if match_type(cx, walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])), &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) { ("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis", diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 4d2e17933ed..d616502a82a 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -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.tables().expr_ty(map)); + let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(map)); return if match_type(cx, obj_ty, &paths::BTREEMAP) { Some(("BTreeMap", map, key)) diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 01eff28cb19..140cd21c34e 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -103,8 +103,8 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { (&ExprKind::Lit(..), _) | (_, &ExprKind::Lit(..)) => {}, // &foo == &bar (&ExprKind::AddrOf(BorrowKind::Ref, _, ref l), &ExprKind::AddrOf(BorrowKind::Ref, _, ref r)) => { - let lty = cx.tables().expr_ty(l); - let rty = cx.tables().expr_ty(r); + let lty = cx.typeck_results().expr_ty(l); + let rty = cx.typeck_results().expr_ty(r); let lcpy = is_copy(cx, lty); let rcpy = is_copy(cx, rty); // either operator autorefs or both args are copyable @@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { ) } else if lcpy && !rcpy - && implements_trait(cx, lty, trait_id, &[cx.tables().expr_ty(right).into()]) + && implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()]) { span_lint_and_then( cx, @@ -145,7 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { ) } else if !lcpy && rcpy - && implements_trait(cx, cx.tables().expr_ty(left), trait_id, &[rty.into()]) + && implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()]) { span_lint_and_then( cx, @@ -166,10 +166,10 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { }, // &foo == bar (&ExprKind::AddrOf(BorrowKind::Ref, _, ref l), _) => { - let lty = cx.tables().expr_ty(l); + let lty = cx.typeck_results().expr_ty(l); let lcpy = is_copy(cx, lty); if (requires_ref || lcpy) - && implements_trait(cx, lty, trait_id, &[cx.tables().expr_ty(right).into()]) + && implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()]) { span_lint_and_then( cx, @@ -190,10 +190,10 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { }, // foo == &bar (_, &ExprKind::AddrOf(BorrowKind::Ref, _, ref r)) => { - let rty = cx.tables().expr_ty(r); + let rty = cx.typeck_results().expr_ty(r); let rcpy = is_copy(cx, rty); if (requires_ref || rcpy) - && implements_trait(cx, cx.tables().expr_ty(left), trait_id, &[rty.into()]) + && implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()]) { span_lint_and_then(cx, OP_REF, e.span, "taken reference of right operand", |diag| { let rsnip = snippet(cx, r.span, "...").to_string(); diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs index 8a268380618..dbd1ff514f0 100644 --- a/clippy_lints/src/erasing_op.rs +++ b/clippy_lints/src/erasing_op.rs @@ -48,7 +48,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.tables(), e) { + if let Some(Constant::Int(0)) = constant_simple(cx, cx.typeck_results(), e) { span_lint( cx, ERASING_OP, diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index ceb3c40d869..82549c12d0a 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { let fn_def_id = cx.tcx.hir().local_def_id(hir_id); cx.tcx.infer_ctxt().enter(|infcx| { - ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.tables()).consume_body(body); + ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body); }); for node in v.set { diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index fb26b9fc27d..87254c1dbc4 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -97,7 +97,7 @@ fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) { // Are the expression or the arguments type-adjusted? Then we need the closure if !(is_adjusted(cx, ex) || args.iter().any(|arg| is_adjusted(cx, arg))); - let fn_ty = cx.tables().expr_ty(caller); + let fn_ty = cx.typeck_results().expr_ty(caller); if matches!(fn_ty.kind, ty::FnDef(_, _) | ty::FnPtr(_) | ty::Closure(_, _)); @@ -128,7 +128,7 @@ fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) { // Are the expression or the arguments type-adjusted? Then we need the closure if !(is_adjusted(cx, ex) || args.iter().skip(1).any(|arg| is_adjusted(cx, arg))); - let method_def_id = cx.tables().type_dependent_def_id(ex.hir_id).unwrap(); + let method_def_id = cx.typeck_results().type_dependent_def_id(ex.hir_id).unwrap(); if !type_is_unsafe_function(cx, cx.tcx.type_of(method_def_id)); if compare_inputs(&mut iter_input_pats(decl, body), &mut args.iter()); @@ -153,7 +153,7 @@ fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) { /// Tries to determine the type for universal function call to be used instead of the closure fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_arg: &Expr<'_>) -> Option { let expected_type_of_self = &cx.tcx.fn_sig(method_def_id).inputs_and_output().skip_binder()[0]; - let actual_type_of_self = &cx.tables().node_type(self_arg.hir_id); + 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) diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 01b0d3c5ede..c00638ecc0c 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -137,7 +137,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { match e.kind { ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => self.report_diverging_sub_expr(e), ExprKind::Call(ref func, _) => { - let typ = self.cx.tables().expr_ty(func); + let typ = self.cx.typeck_results().expr_ty(func); match typ.kind { ty::FnDef(..) | ty::FnPtr(_) => { let sig = typ.fn_sig(self.cx.tcx); @@ -149,7 +149,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { } }, ExprKind::MethodCall(..) => { - let borrowed_table = self.cx.tables(); + let borrowed_table = self.cx.typeck_results(); if borrowed_table.expr_ty(e).is_never() { self.report_diverging_sub_expr(e); } diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index 01ed0c426d4..000762334f6 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -73,7 +73,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h struct FindPanicUnwrap<'a, 'tcx> { lcx: &'a LateContext<'tcx>, - tables: &'tcx ty::TypeckTables<'tcx>, + typeck_results: &'tcx ty::TypeckResults<'tcx>, result: Vec, } @@ -96,7 +96,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.tables.expr_ty(&arglists[0][0])); + let reciever_ty = walk_ptrs_ty(self.typeck_results.expr_ty(&arglists[0][0])); if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type)) || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type)) { @@ -124,7 +124,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h let impl_item_def_id = cx.tcx.hir().local_def_id(impl_item.id.hir_id); let mut fpu = FindPanicUnwrap { lcx: cx, - tables: cx.tcx.typeck_tables_of(impl_item_def_id), + typeck_results: cx.tcx.typeck(impl_item_def_id), result: Vec::new(), }; fpu.visit_expr(&body.value); diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index a3d2a949535..358b9f6dcd0 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -61,7 +61,7 @@ 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<'_>) { if_chain! { - let ty = cx.tables().expr_ty(expr); + 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/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 3087d6a940a..93f6ec92ec7 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -112,7 +112,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.tables(), 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 { @@ -136,7 +136,7 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su if_chain! { // 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.tables().expr_ty(expr).kind; + 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 { @@ -188,7 +188,10 @@ fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { rhs, ) = &args[0].kind { - let recv = match (constant(cx, cx.tables(), lhs), constant(cx, cx.tables(), rhs)) { + let recv = match ( + 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, _ => return, @@ -233,7 +236,7 @@ fn get_integer_from_float_constant(value: &Constant) -> Option { fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { // Check receiver - if let Some((value, _)) = constant(cx, cx.tables(), &args[0]) { + if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) { let method = if F32(f32_consts::E) == value || F64(f64_consts::E) == value { "exp" } else if F32(2.0) == value || F64(2.0) == value { @@ -254,7 +257,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { } // Check argument - if let Some((value, _)) = constant(cx, cx.tables(), &args[1]) { + if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) { let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { ( SUBOPTIMAL_FLOPS, @@ -294,7 +297,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { } fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { - if let Some((value, _)) = constant(cx, cx.tables(), &args[1]) { + if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) { if value == Int(2) { if let Some(parent) = get_parent_expr(cx, expr) { if let Some(grandparent) = get_parent_expr(cx, parent) { @@ -382,8 +385,8 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option { _ ) = add_rhs.kind; if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi"; - if let Some((lvalue, _)) = constant(cx, cx.tables(), &largs[1]); - if let Some((rvalue, _)) = constant(cx, cx.tables(), &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], ".."))); @@ -413,11 +416,11 @@ fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, ref lhs, ref rhs) = expr.kind; - if cx.tables().expr_ty(lhs).is_floating_point(); - if let Some((value, _)) = constant(cx, cx.tables(), rhs); + 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 cx.tables().expr_ty(&method_args[0]).is_floating_point(); + if cx.typeck_results().expr_ty(&method_args[0]).is_floating_point(); if path.ident.name.as_str() == "exp"; then { span_lint_and_sugg( @@ -439,8 +442,8 @@ 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 cx.tables().expr_ty(lhs).is_floating_point(); - if cx.tables().expr_ty(rhs).is_floating_point(); + 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)); } @@ -527,7 +530,7 @@ fn are_exprs_equal(cx: &LateContext<'_>, expr1: &Expr<'_>, expr2: &Expr<'_>) -> /// Returns true iff expr is some zero literal fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - match constant_simple(cx, cx.tables(), expr) { + match constant_simple(cx, cx.typeck_results(), expr) { Some(Constant::Int(i)) => i == 0, Some(Constant::F32(f)) => f == 0.0, Some(Constant::F64(f)) => f == 0.0, @@ -662,8 +665,8 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { mul_lhs, mul_rhs, ) = &div_lhs.kind; - if let Some((rvalue, _)) = constant(cx, cx.tables(), div_rhs); - if let Some((lvalue, _)) = constant(cx, cx.tables(), 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) && @@ -699,7 +702,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 { - let recv_ty = cx.tables().expr_ty(&args[0]); + let recv_ty = cx.typeck_results().expr_ty(&args[0]); if recv_ty.is_floating_point() { match &*path.ident.name.as_str() { diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 33b6bfc459f..572c839502f 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -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.tables().pat_ty(&pats[0])); + let ty = walk_ptrs_ty(cx.typeck_results().pat_ty(&pats[0])); if ty.kind != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym!(string_type)) { return None; } diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 63133a4872a..3ee0b3f74b8 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -392,11 +392,11 @@ impl<'tcx> Functions { .collect::>(); if !raw_ptrs.is_empty() { - let tables = cx.tcx.body_tables(body.id()); + let typeck_results = cx.tcx.typeck_body(body.id()); let mut v = DerefVisitor { cx, ptrs: raw_ptrs, - tables, + typeck_results, }; intravisit::walk_expr(&mut v, expr); @@ -494,13 +494,8 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut FxHashSet< return false; // ignore `_` patterns } let def_id = pat.hir_id.owner.to_def_id(); - if cx.tcx.has_typeck_tables(def_id) { - is_mutable_ty( - cx, - &cx.tcx.typeck_tables_of(def_id.expect_local()).pat_ty(pat), - pat.span, - tys, - ) + if cx.tcx.has_typeck_results(def_id) { + is_mutable_ty(cx, &cx.tcx.typeck(def_id.expect_local()).pat_ty(pat), pat.span, tys) } else { false } @@ -539,7 +534,7 @@ fn raw_ptr_arg(arg: &hir::Param<'_>, ty: &hir::Ty<'_>) -> Option { struct DerefVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, ptrs: FxHashSet, - tables: &'a ty::TypeckTables<'tcx>, + typeck_results: &'a ty::TypeckResults<'tcx>, } impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> { @@ -548,7 +543,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) => { - let ty = self.tables.expr_ty(f); + let ty = self.typeck_results.expr_ty(f); if type_is_unsafe_function(self.cx, ty) { for arg in args { @@ -557,7 +552,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> { } }, hir::ExprKind::MethodCall(_, _, args, _) => { - let def_id = self.tables.type_dependent_def_id(expr.hir_id).unwrap(); + 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) { @@ -614,10 +609,10 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { let mut tys = FxHashSet::default(); for arg in args { let def_id = arg.hir_id.owner.to_def_id(); - if self.cx.tcx.has_typeck_tables(def_id) + if self.cx.tcx.has_typeck_results(def_id) && is_mutable_ty( self.cx, - self.cx.tcx.typeck_tables_of(def_id.expect_local()).expr_ty(arg), + self.cx.tcx.typeck(def_id.expect_local()).expr_ty(arg), arg.span, &mut tys, ) diff --git a/clippy_lints/src/get_last_with_len.rs b/clippy_lints/src/get_last_with_len.rs index 2d93ecc00a7..48ebcf5ebcd 100644 --- a/clippy_lints/src/get_last_with_len.rs +++ b/clippy_lints/src/get_last_with_len.rs @@ -54,7 +54,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.tables().expr_ty(struct_calling_on); + let struct_ty = cx.typeck_results().expr_ty(struct_calling_on); if is_type_diagnostic_item(cx, struct_ty, sym!(vec_type)); // Argument to "get" is a subtraction diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index dc9d636bc6d..4c62637858c 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -62,8 +62,8 @@ fn is_allowed(cx: &LateContext<'_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_ // `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.tables(), right); - if let Some(Constant::Int(1)) = constant_simple(cx, cx.tables(), left); + 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; } @@ -74,8 +74,8 @@ fn is_allowed(cx: &LateContext<'_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_ #[allow(clippy::cast_possible_wrap)] fn check(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span) { - if let Some(Constant::Int(v)) = constant_simple(cx, cx.tables(), e) { - let check = match cx.tables().expr_ty(e).kind { + if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e) { + let check = match cx.typeck_results().expr_ty(e).kind { ty::Int(ity) => unsext(cx.tcx, -1_i128, ity), ty::Uint(uty) => clip(cx.tcx, !0, uty), _ => return, diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index fbd2eeacc6e..2e55094d90c 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -146,7 +146,7 @@ fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Opt if_chain! { if let ExprKind::MethodCall(path, _span, args, _) = &expr.kind; if path.ident.to_string() == "lock"; - let ty = cx.tables().expr_ty(&args[0]); + let ty = cx.typeck_results().expr_ty(&args[0]); if is_type_diagnostic_item(cx, ty, sym!(mutex_type)); then { Some(&args[0]) diff --git a/clippy_lints/src/if_let_some_result.rs b/clippy_lints/src/if_let_some_result.rs index 9e2989dc01e..5b22df5fe49 100644 --- a/clippy_lints/src/if_let_some_result.rs +++ b/clippy_lints/src/if_let_some_result.rs @@ -45,7 +45,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.tables().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/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index f38530aca0c..5f931a0adde 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { }; // Check if the variable in the condition statement is an integer - if !cx.tables().expr_ty(cond_var).is_integral() { + if !cx.typeck_results().expr_ty(cond_var).is_integral() { return; } @@ -93,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { ExprKind::Lit(ref cond_lit) => { // Check if the constant is zero if let LitKind::Int(0, _) = cond_lit.node { - if cx.tables().expr_ty(cond_left).is_signed() { + if cx.typeck_results().expr_ty(cond_left).is_signed() { } else { print_lint_and_sugg(cx, &var_name, expr); }; diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 5857a405b0c..a1f58e54ae3 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 { - let ty = cx.tables().expr_ty(array); + let ty = cx.typeck_results().expr_ty(array); if let Some(range) = higher::range(cx, index) { // Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..] if let ty::Array(_, s) = ty.kind { @@ -143,7 +143,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { // Catchall non-range index, i.e., [n] or [n << m] if let ty::Array(..) = ty.kind { // Index is a constant uint. - if let Some(..) = constant(cx, cx.tables(), index) { + if let Some(..) = constant(cx, cx.typeck_results(), index) { // Let rustc's `const_err` lint handle constant `usize` indexing on arrays. return; } @@ -169,14 +169,18 @@ fn to_const_range<'tcx>( range: higher::Range<'_>, array_size: u128, ) -> (Option, Option) { - let s = range.start.map(|expr| constant(cx, cx.tables(), expr).map(|(c, _)| c)); + let s = range + .start + .map(|expr| constant(cx, cx.typeck_results(), expr).map(|(c, _)| c)); 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.tables(), expr).map(|(c, _)| c)); + let e = range + .end + .map(|expr| constant(cx, cx.typeck_results(), expr).map(|(c, _)| c)); let end = match e { Some(Some(Constant::Int(x))) => { if range.limits == RangeLimits::Closed { diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 3ffc2dd60d9..e511d3ea330 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -231,13 +231,13 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { } if method.ident.name == sym!(last) && args.len() == 1 { let not_double_ended = get_trait_def_id(cx, &paths::DOUBLE_ENDED_ITERATOR).map_or(false, |id| { - !implements_trait(cx, cx.tables().expr_ty(&args[0]), id, &[]) + !implements_trait(cx, cx.typeck_results().expr_ty(&args[0]), id, &[]) }); if not_double_ended { return is_infinite(cx, &args[0]); } } else if method.ident.name == sym!(collect) { - let ty = cx.tables().expr_ty(expr); + let ty = cx.typeck_results().expr_ty(expr); if INFINITE_COLLECTORS.iter().any(|path| match_type(cx, ty, path)) { return is_infinite(cx, &args[0]); } diff --git a/clippy_lints/src/integer_division.rs b/clippy_lints/src/integer_division.rs index e754c7b482a..31181c10d23 100644 --- a/clippy_lints/src/integer_division.rs +++ b/clippy_lints/src/integer_division.rs @@ -50,7 +50,7 @@ fn is_integer_division<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) if let hir::ExprKind::Binary(binop, left, right) = &expr.kind; if let hir::BinOpKind::Div = &binop.node; then { - let (left_ty, right_ty) = (cx.tables().expr_ty(left), cx.tables().expr_ty(right)); + 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/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs index 8eb986c25ff..a7c71587923 100644 --- a/clippy_lints/src/large_stack_arrays.rs +++ b/clippy_lints/src/large_stack_arrays.rs @@ -42,7 +42,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let ExprKind::Repeat(_, _) = expr.kind; - if let ty::Array(element_type, cst) = cx.tables().expr_ty(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 Ok(element_count) = element_count.to_machine_usize(&cx.tcx); diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 1b09328ceab..00d0b8b4e5b 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -300,7 +300,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { return false; } - let ty = &walk_ptrs_ty(cx.tables().expr_ty(expr)); + let ty = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr)); match ty.kind { ty::Dynamic(ref tt, ..) => tt.principal().map_or(false, |principal| { cx.tcx diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 706c73ce66c..8243b0a29bc 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -73,7 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { then { let span = stmt.span.to(if_.span); - let has_interior_mutability = !cx.tables().node_type(canonical_id).is_freeze( + let has_interior_mutability = !cx.typeck_results().node_type(canonical_id).is_freeze( cx.tcx.at(span), cx.param_env, ); diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index c7dda3c9928..ae2f6131b5b 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -76,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { if let PatKind::Wild = local.pat.kind; if let Some(ref init) = local.init; then { - let init_ty = cx.tables().expr_ty(init); + 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)) @@ -94,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "consider using an underscore-prefixed named \ binding or dropping explicitly with `std::mem::drop`" ) - } else if is_must_use_ty(cx, cx.tables().expr_ty(init)) { + } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) { span_lint_and_help( cx, LET_UNDERSCORE_MUST_USE, diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 396bb659109..7e3876ff49b 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -535,7 +535,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops { 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 implements_trait(cx, cx.tables().expr_ty(iter_expr), iter_def_id, &[]); + if implements_trait(cx, cx.typeck_results().expr_ty(iter_expr), iter_def_id, &[]); then { return; } @@ -981,8 +981,8 @@ fn detect_manual_memcpy<'tcx>( if_chain! { if let ExprKind::Index(seqexpr_left, idx_left) = lhs.kind; if let ExprKind::Index(seqexpr_right, idx_right) = rhs.kind; - if is_slice_like(cx, cx.tables().expr_ty(seqexpr_left)) - && is_slice_like(cx, cx.tables().expr_ty(seqexpr_right)); + if is_slice_like(cx, cx.typeck_results().expr_ty(seqexpr_left)) + && is_slice_like(cx, cx.typeck_results().expr_ty(seqexpr_right)); if let Some(offset_left) = get_offset(cx, &idx_left, canonical_id); if let Some(offset_right) = get_offset(cx, &idx_right, canonical_id); @@ -1250,8 +1250,8 @@ fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, expr: lint_iter_method(cx, args, arg, method_name); } } 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]); + let receiver_ty = cx.typeck_results().expr_ty(&args[0]); + let receiver_ty_adjusted = cx.typeck_results().expr_ty_adjusted(&args[0]); 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); @@ -1296,7 +1296,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.tables().expr_ty(arg); + let ty = cx.typeck_results().expr_ty(arg); if is_type_diagnostic_item(cx, ty, sym!(option_type)) { span_lint_and_help( cx, @@ -1400,8 +1400,9 @@ fn check_for_loop_explicit_counter<'tcx>( /// If `arg` was the argument to a `for` loop, return the "cleanest" way of writing the /// actual `Iterator` that the loop uses. 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| implements_trait(cx, cx.tables().expr_ty(arg), id, &[])); + let impls_iterator = get_trait_def_id(cx, &paths::ITERATOR).map_or(false, |id| { + implements_trait(cx, cx.typeck_results().expr_ty(arg), id, &[]) + }); if impls_iterator { format!( "{}", @@ -1412,7 +1413,7 @@ fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic_ref: &mut // (&mut x).into_iter() ==> x.iter_mut() match &arg.kind { ExprKind::AddrOf(BorrowKind::Ref, mutability, arg_inner) - if has_iter_method(cx, cx.tables().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", @@ -1445,7 +1446,7 @@ fn check_for_loop_over_map_kv<'tcx>( if let PatKind::Tuple(ref pat, _) = pat.kind { if pat.len() == 2 { let arg_span = arg.span; - let (new_pat_span, kind, ty, mutbl) = match cx.tables().expr_ty(arg).kind { + let (new_pat_span, kind, ty, mutbl) = match cx.typeck_results().expr_ty(arg).kind { ty::Ref(_, ty, mutbl) => match (&pat[0].kind, &pat[1].kind) { (key, _) if pat_is_wild(key, body) => (pat[1].span, "value", ty, mutbl), (_, value) if pat_is_wild(value, body) => (pat[0].span, "key", ty, Mutability::Not), @@ -1590,7 +1591,14 @@ fn check_for_mutation<'tcx>( }; let def_id = body.hir_id.owner.to_def_id(); cx.tcx.infer_ctxt().enter(|infcx| { - ExprUseVisitor::new(&mut delegate, &infcx, def_id.expect_local(), cx.param_env, cx.tables()).walk_expr(body); + ExprUseVisitor::new( + &mut delegate, + &infcx, + def_id.expect_local(), + cx.param_env, + cx.typeck_results(), + ) + .walk_expr(body); }); delegate.mutation_span() } @@ -1684,7 +1692,7 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> { if index_used_directly { self.indexed_directly.insert( seqvar.segments[0].ident.name, - (Some(extent), self.cx.tables().node_type(seqexpr.hir_id)), + (Some(extent), self.cx.typeck_results().node_type(seqexpr.hir_id)), ); } return false; // no need to walk further *on the variable* @@ -1696,7 +1704,7 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> { if index_used_directly { self.indexed_directly.insert( seqvar.segments[0].ident.name, - (None, self.cx.tables().node_type(seqexpr.hir_id)), + (None, self.cx.typeck_results().node_type(seqexpr.hir_id)), ); } return false; // no need to walk further *on the variable* @@ -1764,7 +1772,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { ExprKind::Call(ref f, args) => { self.visit_expr(f); for expr in args { - let ty = self.cx.tables().expr_ty_adjusted(expr); + let ty = self.cx.typeck_results().expr_ty_adjusted(expr); self.prefer_mutable = false; if let ty::Ref(_, _, mutbl) = ty.kind { if mutbl == Mutability::Mut { @@ -1775,7 +1783,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { } }, ExprKind::MethodCall(_, _, args, _) => { - let def_id = self.cx.tables().type_dependent_def_id(expr.hir_id).unwrap(); + let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); for (ty, expr) in self.cx.tcx.fn_sig(def_id).inputs().skip_binder().iter().zip(args) { self.prefer_mutable = false; if let ty::Ref(_, _, mutbl) = ty.kind { @@ -1862,7 +1870,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarUsedAfterLoopVisitor<'a, 'tcx> { fn is_ref_iterable_type(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { // no walk_ptrs_ty: calling iter() on a reference can make sense because it // will allow further borrows afterwards - let ty = cx.tables().expr_ty(e); + 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) || @@ -2221,7 +2229,7 @@ fn path_name(e: &Expr<'_>) -> Option { } fn check_infinite_loop<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) { - if constant(cx, cx.tables(), cond).is_some() { + if constant(cx, cx.typeck_results(), cond).is_some() { // A pure constant condition (e.g., `while false`) is not linted. return; } @@ -2357,7 +2365,7 @@ fn check_needless_collect<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) { if let Some(ref generic_args) = chain_method.args; if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0); then { - let ty = cx.tables().node_type(ty.hir_id); + 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) || diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 905a3f3ca71..641e6a17043 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 let hir::ExprKind::MethodCall(ref method, _, ref args, _) = e.kind; if args.len() == 2; if method.ident.as_str() == "map"; - let ty = cx.tables().expr_ty(&args[0]); + 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; let closure_body = cx.tcx.hir().body(body_id); @@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { match closure_expr.kind { hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner) => { if ident_eq(name, inner) { - if let ty::Ref(.., Mutability::Not) = cx.tables().expr_ty(inner).kind { + if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind { lint(cx, e.span, args[0].span, true); } } @@ -79,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { if ident_eq(name, &obj[0]) && method.ident.as_str() == "clone" && match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) { - let obj_ty = cx.tables().expr_ty(&obj[0]); + let obj_ty = cx.typeck_results().expr_ty(&obj[0]); if let ty::Ref(_, ty, _) = obj_ty.kind { let copy = is_copy(cx, ty); lint(cx, e.span, args[0].span, copy); diff --git a/clippy_lints/src/map_identity.rs b/clippy_lints/src/map_identity.rs index 24ec78c8846..d4c2e66ff4b 100644 --- a/clippy_lints/src/map_identity.rs +++ b/clippy_lints/src/map_identity.rs @@ -63,7 +63,7 @@ fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a if_chain! { if let ExprKind::MethodCall(ref method, _, ref args, _) = expr.kind; if args.len() == 2 && method.ident.as_str() == "map"; - let caller_ty = cx.tables().expr_ty(&args[0]); + 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)); @@ -119,7 +119,7 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { /// Returns true iff an expression returns the same thing as a parameter's pattern fn match_expr_param(cx: &LateContext<'_>, expr: &Expr<'_>, pat: &Pat<'_>) -> bool { if let PatKind::Binding(_, _, ident, _) = pat.kind { - match_var(expr, ident.name) && !(cx.tables().hir_owner == expr.hir_id.owner && is_adjusted(cx, expr)) + match_var(expr, ident.name) && !(cx.typeck_results().hir_owner == expr.hir_id.owner && is_adjusted(cx, expr)) } else { false } diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 316a71c5005..198251c58dd 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -101,7 +101,7 @@ fn is_unit_type(ty: Ty<'_>) -> bool { } fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { - let ty = cx.tables().expr_ty(expr); + let ty = cx.typeck_results().expr_ty(expr); if let ty::FnDef(id, _) = ty.kind { if let Some(fn_type) = cx.tcx.fn_sig(id).no_bound_vars() { @@ -112,7 +112,7 @@ fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { } fn is_unit_expression(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { - is_unit_type(cx.tables().expr_ty(expr)) + is_unit_type(cx.typeck_results().expr_ty(expr)) } /// The expression inside a closure may or may not have surrounding braces and @@ -205,13 +205,14 @@ fn suggestion_msg(function_type: &str, map_type: &str) -> String { fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr<'_>, map_args: &[hir::Expr<'_>]) { let var_arg = &map_args[0]; - let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.tables().expr_ty(var_arg), sym!(option_type)) { - ("Option", "Some", OPTION_MAP_UNIT_FN) - } else if is_type_diagnostic_item(cx, cx.tables().expr_ty(var_arg), sym!(result_type)) { - ("Result", "Ok", RESULT_MAP_UNIT_FN) - } else { - return; - }; + let (map_type, variant, lint) = + 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)) { + ("Result", "Ok", RESULT_MAP_UNIT_FN) + } else { + return; + }; let fn_arg = &map_args[1]; if is_unit_function(cx, fn_arg) { diff --git a/clippy_lints/src/match_on_vec_items.rs b/clippy_lints/src/match_on_vec_items.rs index 0003aa94a03..4f8f2cb171d 100644 --- a/clippy_lints/src/match_on_vec_items.rs +++ b/clippy_lints/src/match_on_vec_items.rs @@ -88,13 +88,13 @@ fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opti } fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let ty = cx.tables().expr_ty(expr); + let ty = cx.typeck_results().expr_ty(expr); let ty = walk_ptrs_ty(ty); is_type_diagnostic_item(cx, ty, sym!(vec_type)) } fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let ty = cx.tables().expr_ty(expr); + let ty = cx.typeck_results().expr_ty(expr); let ty = walk_ptrs_ty(ty); match_type(cx, ty, &utils::paths::RANGE_FULL) } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index bd474c20807..ea6fb9e9025 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -620,7 +620,7 @@ fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp return; }; - let ty = cx.tables().expr_ty(ex); + let ty = cx.typeck_results().expr_ty(ex); if ty.kind != ty::Bool || is_allowed(cx, MATCH_BOOL, ex.hir_id) { check_single_match_single_pattern(cx, ex, arms, expr, els); check_single_match_opt_like(cx, ex, arms, expr, ty, els); @@ -712,7 +712,7 @@ fn check_single_match_opt_like( fn check_match_bool(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) { // Type of expression is `bool`. - if cx.tables().expr_ty(ex).kind == ty::Bool { + if cx.typeck_results().expr_ty(ex).kind == ty::Bool { span_lint_and_then( cx, MATCH_BOOL, @@ -775,8 +775,8 @@ fn check_match_bool(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: } fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) { - if arms.len() >= 2 && cx.tables().expr_ty(ex).is_integral() { - let ranges = all_ranges(cx, arms, cx.tables().expr_ty(ex)); + if arms.len() >= 2 && cx.typeck_results().expr_ty(ex).is_integral() { + let ranges = all_ranges(cx, arms, cx.typeck_results().expr_ty(ex)); let type_ranges = type_ranges(&ranges); if !type_ranges.is_empty() { if let Some((start, end)) = overlapping(&type_ranges) { @@ -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.tables().expr_ty(ex)); + let ex_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(ex)); 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 { @@ -835,7 +835,7 @@ fn check_wild_err_arm(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { } fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { - let ty = cx.tables().expr_ty(ex); + let ty = cx.typeck_results().expr_ty(ex); if !ty.is_enum() { // If there isn't a nice closed set of possible values that can be conveniently enumerated, // don't complain about not enumerating the mall. @@ -1010,8 +1010,8 @@ fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp "as_mut" }; - let output_ty = cx.tables().expr_ty(expr); - let input_ty = cx.tables().expr_ty(ex); + 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(_, substs) = input_ty.kind; @@ -1079,7 +1079,7 @@ fn check_match_like_matches<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>, desugared: bool) { if_chain! { if arms.len() == 2; - if cx.tables().expr_ty(expr).is_bool(); + if cx.typeck_results().expr_ty(expr).is_bool(); if is_wild(&arms[1].pat); if let Some(first) = find_bool_lit(&arms[0].body.kind, desugared); if let Some(second) = find_bool_lit(&arms[1].body.kind, desugared); @@ -1154,13 +1154,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.tables().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.tables().expr_ty(&match_body).is_unit() { + if cx.typeck_results().expr_ty(&match_body).is_unit() { snippet_body.push(';'); } }, @@ -1255,11 +1255,11 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) { if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind { let lhs = match lhs { - Some(lhs) => constant(cx, cx.tables(), lhs)?.0, + Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0, None => miri_to_const(ty.numeric_min_val(cx.tcx)?)?, }; let rhs = match rhs { - Some(rhs) => constant(cx, cx.tables(), rhs)?.0, + Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0, None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?, }; let rhs = match range_end { @@ -1273,7 +1273,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) } if let PatKind::Lit(ref value) = pat.kind { - let value = constant(cx, cx.tables(), value)?.0; + let value = constant(cx, cx.typeck_results(), value)?.0; return Some(SpannedRange { span: pat.span, node: (value.clone(), Bound::Included(value)), diff --git a/clippy_lints/src/mem_discriminant.rs b/clippy_lints/src/mem_discriminant.rs index 06c56851303..c71c2ee7d70 100644 --- a/clippy_lints/src/mem_discriminant.rs +++ b/clippy_lints/src/mem_discriminant.rs @@ -38,7 +38,7 @@ impl<'tcx> LateLintPass<'tcx> for MemDiscriminant { 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_DISCRIMINANT); // type is non-enum - let ty_param = cx.tables().node_substs(func.hir_id).type_at(0); + let ty_param = cx.typeck_results().node_substs(func.hir_id).type_at(0); if !ty_param.is_enum(); then { diff --git a/clippy_lints/src/mem_forget.rs b/clippy_lints/src/mem_forget.rs index b895ba324c7..8c6fd10f98a 100644 --- a/clippy_lints/src/mem_forget.rs +++ b/clippy_lints/src/mem_forget.rs @@ -31,7 +31,7 @@ impl<'tcx> LateLintPass<'tcx> for MemForget { if let ExprKind::Path(ref qpath) = path_expr.kind { if let Some(def_id) = qpath_res(cx, qpath, path_expr.hir_id).opt_def_id() { if match_def_path(cx, def_id, &paths::MEM_FORGET) { - let forgot_ty = cx.tables().expr_ty(&args[0]); + let forgot_ty = cx.typeck_results().expr_ty(&args[0]); 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/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 25f332cdcc2..bb0acecc5a9 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -138,7 +138,7 @@ fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &E fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { if_chain! { // check if replacement is mem::MaybeUninit::uninit().assume_init() - if let Some(method_def_id) = cx.tables().type_dependent_def_id(src.hir_id); + 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 { let mut applicability = Applicability::MachineApplicable; @@ -179,7 +179,7 @@ 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.tables().expr_ty(src).is_primitive() { + !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 fcf7b509ead..498f12518f8 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -157,7 +157,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<'_>]) { - if !match_type(cx, cx.tables().expr_ty(&args[0]), Self::TYPE_QPATH) { + if !match_type(cx, cx.typeck_results().expr_ty(&args[0]), Self::TYPE_QPATH) { return; } diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index 1c0018a5b95..e5f815772eb 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -11,9 +11,9 @@ use rustc_middle::ty::{self, Ty}; /// Checks for the `INEFFICIENT_TO_STRING` lint pub fn lint<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'tcx>) { if_chain! { - if let Some(to_string_meth_did) = cx.tables().type_dependent_def_id(expr.hir_id); + 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.tables().node_substs_opt(expr.hir_id); + if let Some(substs) = cx.typeck_results().node_substs_opt(expr.hir_id); let self_ty = substs.type_at(0); let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty); if deref_count >= 1; diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 9c04b6d57b9..40a62575861 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -11,7 +11,7 @@ pub fn lint(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[&[hir::Expr<'_>] let arith_lhs = &args[1][0]; let arith_rhs = &args[1][1]; - let ty = cx.tables().expr_ty(arith_lhs); + let ty = cx.typeck_results().expr_ty(arith_lhs); if !ty.is_integral() { return; } @@ -101,7 +101,7 @@ fn is_min_or_max<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) -> Option LateLintPass<'tcx> for Methods { 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); - let self_ty = cx.tables().expr_ty_adjusted(&args[0]); + 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]); @@ -1639,7 +1639,7 @@ fn lint_or_fun_call<'tcx>( 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.tables().expr_ty(arg); + 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, &[]); @@ -1679,7 +1679,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.tables().expr_ty(&args[0])); + let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])); match ty.kind { ty::Slice(_) | ty::Array(_, _) => return, @@ -1707,7 +1707,7 @@ fn lint_or_fun_call<'tcx>( if { finder.visit_expr(&arg); finder.found }; if !contains_return(&arg); - let self_ty = cx.tables().expr_ty(self_expr); + 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)); @@ -1786,7 +1786,7 @@ fn lint_expect_fun_call( if call_args.len() == 1 && (method_name.ident.name == sym!(as_str) || method_name.ident.name == sym!(as_ref)) && { - let arg_type = cx.tables().expr_ty(&call_args[0]); + let arg_type = cx.typeck_results().expr_ty(&call_args[0]); let base_type = walk_ptrs_ty(arg_type); base_type.kind == ty::Str || is_type_diagnostic_item(cx, base_type, sym!(string_type)) } @@ -1805,7 +1805,7 @@ fn lint_expect_fun_call( // 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.tables().expr_ty(arg); + let arg_ty = cx.typeck_results().expr_ty(arg); if is_type_diagnostic_item(cx, arg_ty, sym!(string_type)) { return false; } @@ -1835,15 +1835,16 @@ fn lint_expect_fun_call( false } }, - hir::ExprKind::MethodCall(..) => cx - .tables() - .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::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, _) @@ -1891,7 +1892,7 @@ fn lint_expect_fun_call( return; } - let receiver_type = cx.tables().expr_ty_adjusted(&args[0]); + 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)) { @@ -1957,7 +1958,7 @@ 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.tables().expr_ty(expr); + 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( @@ -2005,7 +2006,9 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp // &*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::ExprKind::MethodCall(_, _, parent_args, _) if expr.hir_id == parent_args[0].hir_id => { + return; + }, _ => {}, }, @@ -2021,11 +2024,11 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp } // x.clone() might have dereferenced x, possibly through Deref impls - if cx.tables().expr_ty(arg) == ty { + if cx.typeck_results().expr_ty(arg) == ty { snip = Some(("try removing the `clone` call", format!("{}", snippet))); } else { let deref_count = cx - .tables() + .typeck_results() .expr_adjustments(arg) .iter() .filter(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(_))) @@ -2045,7 +2048,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.tables().expr_ty(arg)); + let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(arg)); if let ty::Adt(_, subst) = obj_ty.kind { let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) { @@ -2079,7 +2082,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.tables().expr_ty(target)); + let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(target)); let ref_str = if self_ty.kind == ty::Str { "" } else if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) { @@ -2107,7 +2110,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.tables().expr_ty(&args[0])); + let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])); if is_type_diagnostic_item(cx, obj_ty, sym!(string_type)) { lint_string_extend(cx, expr, args); } @@ -2115,7 +2118,7 @@ fn lint_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_> fn lint_cstring_as_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, source: &hir::Expr<'_>, unwrap: &hir::Expr<'_>) { if_chain! { - let source_type = cx.tables().expr_ty(source); + let source_type = cx.typeck_results().expr_ty(source); if let ty::Adt(def, substs) = source_type.kind; if cx.tcx.is_diagnostic_item(sym!(result_type), def.did); if match_type(cx, substs.type_at(0), &paths::CSTRING); @@ -2135,8 +2138,8 @@ fn lint_cstring_as_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, source: &hir: 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.tables().expr_ty(expr), sym!(vec_type)); - if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.tables().expr_ty(&iter_args[0])); + 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 { @@ -2243,7 +2246,7 @@ 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.tables(), &args[1]) { + if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &args[1]) { span_lint( cx, ITERATOR_STEP_BY_ZERO, @@ -2267,7 +2270,7 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_ parent_expr_opt = get_parent_expr(cx, parent_expr); } - if derefs_to_slice(cx, caller_expr, cx.tables().expr_ty(caller_expr)).is_some() { + 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; @@ -2288,8 +2291,11 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_ ); } } - } 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(_, _)) + } 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, + ty::Array(_, _) + ) { // caller is a Vec or an Array let mut applicability = Applicability::MachineApplicable; @@ -2316,11 +2322,11 @@ fn lint_iter_nth<'tcx>( ) { 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.tables().expr_ty(&iter_args[0])).is_some() { + 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.tables().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.tables().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]; @@ -2341,7 +2347,7 @@ fn lint_iter_nth<'tcx>( 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.tables(), &nth_args[1]); + if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), &nth_args[1]); then { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( @@ -2361,7 +2367,7 @@ fn lint_get_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args: // 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.tables().expr_ty(&get_args[0]); + 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 { @@ -2463,7 +2469,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.tables().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 @@ -2486,7 +2492,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.tables().expr_ty(&unwrap_args[0])); + let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&unwrap_args[0])); let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) { Some((UNWRAP_USED, "an Option", "None")) @@ -2514,7 +2520,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.tables().expr_ty(&expect_args[0])); + let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&expect_args[0])); let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) { Some((EXPECT_USED, "an Option", "None")) @@ -2540,8 +2546,8 @@ 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.tables().expr_ty(&ok_args[0]), sym!(result_type)); - let result_type = cx.tables().expr_ty(&ok_args[0]); + 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); @@ -2579,7 +2585,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.tables().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 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, ".."); @@ -2605,8 +2611,8 @@ fn lint_map_unwrap_or_else<'tcx>( unwrap_args: &'tcx [hir::Expr<'_>], ) { // lint if the caller of `map()` is an `Option` - let is_option = is_type_diagnostic_item(cx, cx.tables().expr_ty(&map_args[0]), sym!(option_type)); - let is_result = is_type_diagnostic_item(cx, cx.tables().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 @@ -2656,8 +2662,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.tables().expr_ty(&map_or_args[0]), sym!(option_type)); - let is_result = is_type_diagnostic_item(cx, cx.tables().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` @@ -3014,7 +3020,7 @@ fn lint_chars_cmp( if segment.ident.name == sym!(Some); then { let mut applicability = Applicability::MachineApplicable; - let self_ty = walk_ptrs_ty(cx.tables().expr_ty_adjusted(&args[0][0])); + let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty_adjusted(&args[0][0])); if self_ty.kind != ty::Str { return false; @@ -3142,8 +3148,8 @@ fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_re 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.tables().expr_ty(recvr); - let res_ty = cx.tables().expr_ty(expr); + 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 { @@ -3212,7 +3218,7 @@ fn lint_maybe_uninit(cx: &LateContext<'_>, expr: &hir::Expr<'_>, outer: &hir::Ex 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.tables().expr_ty_adjusted(outer)); + if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(outer)); then { span_lint( cx, @@ -3254,7 +3260,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.tables().expr_ty(&as_ref_args[0]); + let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]); if !is_type_diagnostic_item(cx, option_ty, sym!(option_type)) { return; } @@ -3284,10 +3290,10 @@ fn lint_option_as_ref_deref<'tcx>( 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; - let adj = cx.tables().expr_adjustments(&args[0]).iter().map(|x| &x.kind).collect::>(); + 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.tables().type_dependent_def_id(closure_expr.hir_id).unwrap(); + 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 @@ -3577,7 +3583,7 @@ fn contains_return(expr: &hir::Expr<'_>) -> 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.tables().expr_ty(&args[0]).kind; + 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 { @@ -3587,7 +3593,7 @@ 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.tables().expr_ty(&args[0]); + let ty = cx.typeck_results().expr_ty(&args[0]); if !match_type(cx, ty, &paths::FILE_TYPE) { return; diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 672eb75c57f..95fa28e1c0f 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -20,8 +20,8 @@ pub(super) fn lint<'tcx>( map_span: Span, ) { // lint if the caller of `map()` is an `Option` - if is_type_diagnostic_item(cx, cx.tables().expr_ty(&map_args[0]), sym!(option_type)) { - if !is_copy(cx, cx.tables().expr_ty(&unwrap_args[1])) { + 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/minmax.rs b/clippy_lints/src/minmax.rs index c8aa98d3489..dae39aaf5e2 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -36,7 +36,7 @@ impl<'tcx> LateLintPass<'tcx> for MinMaxPass { } match ( outer_max, - Constant::partial_cmp(cx.tcx, cx.tables().expr_ty(ie), &outer_c, &inner_c), + Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(ie), &outer_c, &inner_c), ) { (_, None) | (MinMax::Max, Some(Ordering::Less)) | (MinMax::Min, Some(Ordering::Greater)) => (), _ => { @@ -62,7 +62,7 @@ enum MinMax { fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Constant, &'a Expr<'a>)> { if let ExprKind::Call(ref path, ref args) = expr.kind { if let ExprKind::Path(ref qpath) = path.kind { - cx.tables() + cx.typeck_results() .qpath_res(qpath, path.hir_id) .opt_def_id() .and_then(|def_id| { @@ -86,10 +86,10 @@ fn fetch_const<'a>(cx: &LateContext<'_>, args: &'a [Expr<'a>], m: MinMax) -> Opt if args.len() != 2 { return None; } - constant_simple(cx, cx.tables(), &args[0]).map_or_else( - || constant_simple(cx, cx.tables(), &args[1]).map(|c| (m, c, &args[0])), + constant_simple(cx, cx.typeck_results(), &args[0]).map_or_else( + || constant_simple(cx, cx.typeck_results(), &args[1]).map(|c| (m, c, &args[0])), |c| { - if constant_simple(cx, cx.tables(), &args[1]).is_none() { + if constant_simple(cx, cx.typeck_results(), &args[1]).is_none() { // otherwise ignore Some((m, c, &args[1])) } else { diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 400f4b609af..fc10e5077b8 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -496,7 +496,7 @@ fn get_lint_and_message( 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.tables(), expr); + if let Some((value, _)) = constant(cx, cx.typeck_results(), expr); then { let needs_lint = match value { Constant::F32(num) => num.is_nan(), @@ -517,7 +517,7 @@ fn check_nan(cx: &LateContext<'_>, expr: &Expr<'_>, cmp_expr: &Expr<'_>) { } fn is_named_constant<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { - if let Some((_, res)) = constant(cx, cx.tables(), expr) { + if let Some((_, res)) = constant(cx, cx.typeck_results(), expr) { res } else { false @@ -525,7 +525,7 @@ fn is_named_constant<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool } fn is_allowed<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { - match constant(cx, cx.tables(), expr) { + 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 { @@ -557,7 +557,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } fn is_float(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - let value = &walk_ptrs_ty(cx.tables().expr_ty(expr)).kind; + let value = &walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind; if let ty::Array(arr_ty, _) = value { return matches!(arr_ty.kind, ty::Float(_)); @@ -567,7 +567,7 @@ fn is_float(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } fn is_array(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - matches!(&walk_ptrs_ty(cx.tables().expr_ty(expr)).kind, ty::Array(_, _)) + matches!(&walk_ptrs_ty(cx.typeck_results().expr_ty(expr)).kind, ty::Array(_, _)) } fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) { @@ -593,7 +593,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 => { if match_trait_method(cx, expr, &paths::TO_STRING) || match_trait_method(cx, expr, &paths::TO_OWNED) { - (cx.tables().expr_ty(&args[0]), snippet(cx, args[0].span, "..")) + (cx.typeck_results().expr_ty(&args[0]), snippet(cx, args[0].span, "..")) } else { return; } @@ -601,7 +601,7 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: ExprKind::Call(ref path, ref 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.tables().expr_ty(&v[0]), snippet(cx, v[0].span, "..")) + (cx.typeck_results().expr_ty(&v[0]), snippet(cx, v[0].span, "..")) } else { return; } @@ -612,7 +612,7 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: _ => return, }; - let other_ty = cx.tables().expr_ty(other); + let other_ty = cx.typeck_results().expr_ty(other); let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default(); let with_deref = arg_ty diff --git a/clippy_lints/src/modulo_arithmetic.rs b/clippy_lints/src/modulo_arithmetic.rs index 59ccc6333fd..5d4436bd206 100644 --- a/clippy_lints/src/modulo_arithmetic.rs +++ b/clippy_lints/src/modulo_arithmetic.rs @@ -37,8 +37,8 @@ struct OperandInfo { } fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { - match constant(cx, cx.tables(), operand) { - Some((Constant::Int(v), _)) => match cx.tables().expr_ty(expr).kind { + match constant(cx, cx.typeck_results(), operand) { + 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 { @@ -106,7 +106,7 @@ fn check_const_operands<'tcx>( } fn check_non_const_operands<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, operand: &Expr<'_>) { - let operand_type = cx.tables().expr_ty(operand); + let operand_type = cx.typeck_results().expr_ty(operand); if might_have_negative_value(operand_type) { span_lint_and_then( cx, diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index d8fb8a4bb77..9f8f401cc0f 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -76,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType { if let hir::PatKind::Wild = local.pat.kind { return; } - check_ty(cx, local.span, cx.tables().pat_ty(&*local.pat)); + check_ty(cx, local.span, cx.typeck_results().pat_ty(&*local.pat)); } } diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs index 259b4c73d76..b02e86bca27 100644 --- a/clippy_lints/src/mut_mut.rs +++ b/clippy_lints/src/mut_mut.rs @@ -69,7 +69,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> { expr.span, "generally you want to avoid `&mut &mut _` if possible", ); - } else if let ty::Ref(_, _, hir::Mutability::Mut) = self.cx.tables().expr_ty(e).kind { + } else if let ty::Ref(_, _, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind { span_lint( self.cx, MUT_MUT, diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index 53341b6eba7..b8dc5081632 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -37,14 +37,14 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { check_arguments( cx, arguments, - cx.tables().expr_ty(fn_expr), + cx.typeck_results().expr_ty(fn_expr), &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)), ); } }, ExprKind::MethodCall(ref path, _, ref arguments, _) => { - let def_id = cx.tables().type_dependent_def_id(e.hir_id).unwrap(); - let substs = cx.tables().node_substs(e.hir_id); + 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()) }, diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 78d2356748f..7f529f0404c 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -135,7 +135,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> { return; }, ExprKind::Path(_) => { - if let Some(adj) = self.cx.tables().adjustments().get(expr.hir_id) { + if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) { if adj .iter() .any(|a| matches!(a.target.kind, ty::Ref(_, _, Mutability::Mut))) diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 1a821491fca..568898aa5c9 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -66,7 +66,7 @@ declare_lint_pass!(Mutex => [MUTEX_ATOMIC, MUTEX_INTEGER]); impl<'tcx> LateLintPass<'tcx> for Mutex { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let ty = cx.tables().expr_ty(expr); + let ty = cx.typeck_results().expr_ty(expr); if let ty::Adt(_, subst) = ty.kind { if is_type_diagnostic_item(cx, ty, sym!(mutex_type)) { let mutex_param = subst.type_at(0); diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index e15376b9326..8e44f2ec240 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -229,7 +229,10 @@ fn check_comparison<'a, 'tcx>( use self::Expression::{Bool, Other}; if let ExprKind::Binary(op, ref left_side, ref right_side) = e.kind { - let (l_ty, r_ty) = (cx.tables().expr_ty(left_side), cx.tables().expr_ty(right_side)); + let (l_ty, r_ty) = ( + cx.typeck_results().expr_ty(left_side), + cx.typeck_results().expr_ty(right_side), + ); if l_ty.is_bool() && r_ty.is_bool() { let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index 1bea93fcb75..415ab556c9f 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -46,8 +46,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow { return; } if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, ref inner) = e.kind { - if let ty::Ref(..) = cx.tables().expr_ty(inner).kind { - for adj3 in cx.tables().expr_adjustments(e).windows(3) { + if let ty::Ref(..) = 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 { @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow { } if_chain! { if let PatKind::Binding(BindingAnnotation::Ref, .., name, _) = pat.kind; - if let ty::Ref(_, tam, mutbl) = cx.tables().pat_ty(pat).kind; + if let ty::Ref(_, tam, mutbl) = cx.typeck_results().pat_ty(pat).kind; if mutbl == Mutability::Not; if let ty::Ref(_, _, mutbl) = tam.kind; // only lint immutable refs, because borrowed `&mut T` cannot be moved out diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 29e5d4d1664..81774b617ac 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -135,7 +135,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { } = { let mut ctx = MovedVariablesCtxt::default(); cx.tcx.infer_ctxt().enter(|infcx| { - euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.tables()).consume_body(body); + euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()) + .consume_body(body); }); ctx }; diff --git a/clippy_lints/src/needless_update.rs b/clippy_lints/src/needless_update.rs index 6ec73041604..ce3f066eff5 100644 --- a/clippy_lints/src/needless_update.rs +++ b/clippy_lints/src/needless_update.rs @@ -47,7 +47,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 { - let ty = cx.tables().expr_ty(expr); + let ty = cx.typeck_results().expr_ty(expr); if let ty::Adt(def, _) = ty.kind { if fields.len() == def.non_enum_variant().fields.len() { span_lint( 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 1be766d8e8d..95613a1b82e 100644 --- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -56,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd { then { - let ty = cx.tables().expr_ty(left); + let ty = cx.typeck_results().expr_ty(left); let implements_ord = { if let Some(id) = utils::get_trait_def_id(cx, &paths::ORD) { diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index 1346145da32..6b6c950e0ab 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -44,8 +44,8 @@ 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.tables().expr_ty_opt(lit)); - if cx.tables().expr_ty(exp).is_integral(); + if let Constant::Int(1) = consts::lit_to_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)); + 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/no_effect.rs b/clippy_lints/src/no_effect.rs index 95283dae714..b1b5b3439a0 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -48,7 +48,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } match expr.kind { ExprKind::Lit(..) | ExprKind::Closure(..) => true, - ExprKind::Path(..) => !has_drop(cx, cx.tables().expr_ty(expr)), + 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) }, @@ -61,7 +61,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { | ExprKind::AddrOf(_, _, ref inner) | ExprKind::Box(ref inner) => has_no_effect(cx, inner), ExprKind::Struct(_, ref fields, ref base) => { - !has_drop(cx, cx.tables().expr_ty(expr)) + !has_drop(cx, cx.typeck_results().expr_ty(expr)) && fields.iter().all(|field| has_no_effect(cx, &field.expr)) && base.as_ref().map_or(true, |base| has_no_effect(cx, base)) }, @@ -70,7 +70,8 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let res = qpath_res(cx, qpath, callee.hir_id); match res { Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..) => { - !has_drop(cx, cx.tables().expr_ty(expr)) && args.iter().all(|arg| has_no_effect(cx, arg)) + !has_drop(cx, cx.typeck_results().expr_ty(expr)) + && args.iter().all(|arg| has_no_effect(cx, arg)) }, _ => false, } @@ -137,7 +138,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option reduce_expression(cx, inner).or_else(|| Some(vec![inner])), ExprKind::Struct(_, ref fields, ref base) => { - if has_drop(cx, cx.tables().expr_ty(expr)) { + 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()) @@ -148,7 +149,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option + if !has_drop(cx, cx.typeck_results().expr_ty(expr)) => { Some(args.iter().collect()) }, diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index a3521c31a6b..031d69e86a1 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -237,13 +237,13 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { } let ty = if needs_check_adjustment { - let adjustments = cx.tables().expr_adjustments(dereferenced_expr); + let adjustments = cx.typeck_results().expr_adjustments(dereferenced_expr); if let Some(i) = adjustments .iter() .position(|adj| matches!(adj.kind, Adjust::Borrow(_) | Adjust::Deref(_))) { if i == 0 { - cx.tables().expr_ty(dereferenced_expr) + cx.typeck_results().expr_ty(dereferenced_expr) } else { adjustments[i - 1].target } @@ -252,7 +252,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { return; } } else { - cx.tables().expr_ty(dereferenced_expr) + cx.typeck_results().expr_ty(dereferenced_expr) }; verify_ty_bound(cx, ty, Source::Expr { expr: expr.span }); diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/open_options.rs index 2b83efa84f6..e99d0317ba2 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/open_options.rs @@ -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.tables().expr_ty(&arguments[0])); + let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&arguments[0])); 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.tables().expr_ty(&arguments[0])); + let obj_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&arguments[0])); // 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/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 8dbe58763bf..065f863b865 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -72,7 +72,8 @@ 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" && match_type(cx, &cx.tables().expr_ty(&receiver), &paths::RESULT) + path.ident.name.to_ident_string() == "ok" + && match_type(cx, &cx.typeck_results().expr_ty(&receiver), &paths::RESULT) } else { false } diff --git a/clippy_lints/src/overflow_check_conditional.rs b/clippy_lints/src/overflow_check_conditional.rs index 0850f88df44..4d4a9676654 100644 --- a/clippy_lints/src/overflow_check_conditional.rs +++ b/clippy_lints/src/overflow_check_conditional.rs @@ -36,8 +36,8 @@ impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional { if let ExprKind::Path(QPath::Resolved(_, ref path2)) = ident2.kind; if let ExprKind::Path(QPath::Resolved(_, ref path3)) = second.kind; if eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]); - if cx.tables().expr_ty(ident1).is_integral(); - if cx.tables().expr_ty(ident2).is_integral(); + 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 { @@ -61,8 +61,8 @@ impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional { if let ExprKind::Path(QPath::Resolved(_, ref path2)) = ident2.kind; if let ExprKind::Path(QPath::Resolved(_, ref path3)) = first.kind; if eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]); - if cx.tables().expr_ty(ident1).is_integral(); - if cx.tables().expr_ty(ident2).is_integral(); + 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 { diff --git a/clippy_lints/src/path_buf_push_overwrite.rs b/clippy_lints/src/path_buf_push_overwrite.rs index 48e60954279..66a145a7f14 100644 --- a/clippy_lints/src/path_buf_push_overwrite.rs +++ b/clippy_lints/src/path_buf_push_overwrite.rs @@ -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.tables().expr_ty(&args[0])), &paths::PATH_BUF); + if match_type(cx, walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])), &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/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs index a49dc87c0b4..ef26fc667b2 100644 --- a/clippy_lints/src/pattern_type_mismatch.rs +++ b/clippy_lints/src/pattern_type_mismatch.rs @@ -87,7 +87,7 @@ 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 Some(init) = &local.init { - if let Some(init_ty) = cx.tables().node_type_opt(init.hir_id) { + if let Some(init_ty) = cx.typeck_results().node_type_opt(init.hir_id) { let pat = &local.pat; if in_external_macro(cx.sess(), pat.span) { return; @@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch { if let ExprKind::Match(ref expr, arms, source) = expr.kind { match source { MatchSource::Normal | MatchSource::IfLetDesugar { .. } | MatchSource::WhileLetDesugar => { - if let Some(expr_ty) = cx.tables().node_type_opt(expr.hir_id) { + if let Some(expr_ty) = cx.typeck_results().node_type_opt(expr.hir_id) { 'pattern_checks: for arm in arms { let pat = &arm.pat; if in_external_macro(cx.sess(), pat.span) { @@ -132,7 +132,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch { _: Span, hir_id: HirId, ) { - if let Some(fn_sig) = cx.tables().liberated_fn_sigs().get(hir_id) { + 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); } diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index 61e186a4b46..0a2d1b5fbe6 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -105,12 +105,12 @@ 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 { - cx.tables().expr_ty(expr) == cx.tcx.types.usize + 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 { - cx.tables().expr_ty(expr).is_unsafe_ptr() + cx.typeck_results().expr_ty(expr).is_unsafe_ptr() } fn build_suggestion<'tcx>( diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index cc9c2f19607..fb12c565afd 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -135,13 +135,13 @@ impl QuestionMark { } fn moves_by_default(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool { - let expr_ty = cx.tables().expr_ty(expression); + let expr_ty = cx.typeck_results().expr_ty(expression); !expr_ty.is_copy_modulo_regions(cx.tcx.at(expression.span), cx.param_env) } fn is_option(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool { - let expr_ty = cx.tables().expr_ty(expression); + let expr_ty = cx.typeck_results().expr_ty(expression); is_type_diagnostic_item(cx, expr_ty, sym!(option_type)) } diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index dd608de5723..4c1f2e8e01a 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -280,10 +280,10 @@ 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(cx, expr); - let ty = cx.tables().expr_ty(start); + let ty = cx.typeck_results().expr_ty(start); if let ty::Int(_) | ty::Uint(_) = ty.kind; - if let Some((start_idx, _)) = constant(cx, cx.tables(), start); - if let Some((end_idx, _)) = constant(cx, cx.tables(), 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 f204a0ffb2c..dfc158661cb 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -89,7 +89,7 @@ fn str_span(base: Span, c: regex_syntax::ast::Span, offset: u16) -> Span { } fn const_str<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option { - constant(cx, cx.tables(), 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/repeat_once.rs b/clippy_lints/src/repeat_once.rs index a3af369e41e..77c206002ea 100644 --- a/clippy_lints/src/repeat_once.rs +++ b/clippy_lints/src/repeat_once.rs @@ -41,10 +41,10 @@ impl<'tcx> LateLintPass<'tcx> for RepeatOnce { if_chain! { if let ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind; if path.ident.name == sym!(repeat); - if let Some(Constant::Int(1)) = constant_context(cx, cx.tables()).expr(&args[1]); + if let Some(Constant::Int(1)) = constant_context(cx, cx.typeck_results()).expr(&args[1]); if !in_macro(args[0].span); then { - let ty = walk_ptrs_ty(cx.tables().expr_ty(&args[0])); + let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])); if ty.is_str() { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index 194786c5c41..901c0a65d7f 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -164,7 +164,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); + let var_ty = cx.typeck_results().node_type_opt(pat_id); var_ty.map_or(false, |var_ty| !matches!(var_ty.kind, ty::Adt(..))) } diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 89aa6a4edd6..bada6fa7c52 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -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.tables().expr_ty(e)), sym!(string_type)) + is_type_diagnostic_item(cx, walk_ptrs_ty(cx.typeck_results().expr_ty(e)), 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 eb7d3583920..754f87e6b55 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -194,7 +194,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 SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, lhs2) { - let ty = walk_ptrs_ty(cx.tables().expr_ty(lhs1)); + let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(lhs1)); if matches!(ty.kind, ty::Slice(_)) || matches!(ty.kind, ty::Array(_, _)) diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index 4157103a574..6750452941f 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { if_chain! { if let [char_arg, radix_arg] = &**to_digit_args; if to_digits_path.ident.name.as_str() == "to_digit"; - let char_arg_ty = cx.tables().expr_ty_adjusted(char_arg); + 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)) diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index 5f76d5c46ef..d55eb1a0c93 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -302,8 +302,8 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { 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); then { - let from_ty = cx.tables().expr_ty(&args[0]); - let to_ty = cx.tables().expr_ty(e); + let from_ty = cx.typeck_results().expr_ty(&args[0]); + let to_ty = cx.typeck_results().expr_ty(e); match (&from_ty.kind, &to_ty.kind) { _ if from_ty == to_ty => span_lint( diff --git a/clippy_lints/src/transmuting_null.rs b/clippy_lints/src/transmuting_null.rs index 2f03c6db42d..fbf7f0b2517 100644 --- a/clippy_lints/src/transmuting_null.rs +++ b/clippy_lints/src/transmuting_null.rs @@ -44,7 +44,7 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull { then { // Catching transmute over constants that resolve to `null`. - let mut const_eval_context = constant_context(cx, cx.tables()); + 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]); diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index 208d248faa5..d3b351f30ef 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { if let Some(return_type) = find_err_return_type(cx, &expr.kind); then { - let err_type = cx.tables().expr_ty(err_arg); + let err_type = cx.typeck_results().expr_ty(err_arg); let origin_snippet = if err_arg.span.from_expansion() { snippet_with_macro_callsite(cx, err_arg.span, "_") } else { @@ -114,7 +114,7 @@ fn find_err_return_type_arm<'tcx>(cx: &LateContext<'tcx>, arm: &'tcx Arm<'_>) -> if match_qpath(from_error_fn, &paths::TRY_FROM_ERROR); if let Some(from_error_arg) = from_error_args.get(0); then { - Some(cx.tables().expr_ty(from_error_arg)) + Some(cx.typeck_results().expr_ty(from_error_arg)) } else { None } diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index bca388ecdcc..c3dea447521 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, TyS, TypeckTables}; +use rustc_middle::ty::{self, InferTy, Ty, TyCtxt, TyS, TypeckResults}; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::Span; @@ -595,7 +595,7 @@ declare_lint_pass!(LetUnitValue => [LET_UNIT_VALUE]); impl<'tcx> LateLintPass<'tcx> for LetUnitValue { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if let StmtKind::Local(ref local) = stmt.kind { - if is_unit(cx.tables().pat_ty(&local.pat)) { + if is_unit(cx.typeck_results().pat_ty(&local.pat)) { if in_external_macro(cx.sess(), stmt.span) || local.pat.span.from_expansion() { return; } @@ -680,7 +680,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitCmp { if let ExpnKind::Macro(MacroKind::Bang, symbol) = callee.kind { if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind { let op = cmp.node; - if op.is_comparison() && is_unit(cx.tables().expr_ty(left)) { + if op.is_comparison() && is_unit(cx.typeck_results().expr_ty(left)) { let result = match &*symbol.as_str() { "assert_eq" | "debug_assert_eq" => "succeed", "assert_ne" | "debug_assert_ne" => "fail", @@ -704,7 +704,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitCmp { } if let ExprKind::Binary(ref cmp, ref left, _) = expr.kind { let op = cmp.node; - if op.is_comparison() && is_unit(cx.tables().expr_ty(left)) { + if op.is_comparison() && is_unit(cx.typeck_results().expr_ty(left)) { let result = match op { BinOpKind::Eq | BinOpKind::Le | BinOpKind::Ge => "true", _ => "false", @@ -774,7 +774,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitArg { let args_to_recover = args .iter() .filter(|arg| { - if is_unit(cx.tables().expr_ty(arg)) && !is_unit_literal(arg) { + if is_unit(cx.typeck_results().expr_ty(arg)) && !is_unit_literal(arg) { !matches!(&arg.kind, ExprKind::Match(.., MatchSource::TryDesugar)) } else { false @@ -1232,7 +1232,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.tables(), op); + 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; @@ -1398,7 +1398,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { return; } if let ExprKind::Cast(ref ex, _) = expr.kind { - let (cast_from, cast_to) = (cx.tables().expr_ty(ex), cx.tables().expr_ty(expr)); + let (cast_from, cast_to) = (cx.typeck_results().expr_ty(ex), cx.typeck_results().expr_ty(expr)); lint_fn_to_numeric_cast(cx, expr, ex, cast_from, cast_to); if let ExprKind::Lit(ref lit) = ex.kind { if_chain! { @@ -1786,7 +1786,7 @@ impl<'tcx> LateLintPass<'tcx> for CharLitAsU8 { 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.tables().expr_ty(expr).kind; + 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); @@ -1862,8 +1862,8 @@ 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 { - let precast_ty = cx.tables().expr_ty(cast_exp); - let cast_ty = cx.tables().expr_ty(expr); + let precast_ty = cx.typeck_results().expr_ty(cast_exp); + let cast_ty = cx.typeck_results().expr_ty(expr); return is_isize_or_usize(precast_ty) != is_isize_or_usize(cast_ty); } @@ -1883,7 +1883,7 @@ fn detect_absurd_comparison<'tcx>( // absurd comparison only makes sense on primitive types // primitive types don't implement comparison operators with each other - if cx.tables().expr_ty(lhs) != cx.tables().expr_ty(rhs) { + if cx.typeck_results().expr_ty(lhs) != cx.typeck_results().expr_ty(rhs) { return None; } @@ -1921,9 +1921,9 @@ fn detect_absurd_comparison<'tcx>( fn detect_extreme_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { use crate::types::ExtremeType::{Maximum, Minimum}; - let ty = cx.tables().expr_ty(expr); + let ty = cx.typeck_results().expr_ty(expr); - let cv = constant(cx, cx.tables(), expr)?.0; + let cv = constant(cx, cx.typeck_results(), expr)?.0; let which = match (&ty.kind, cv) { (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => Minimum, @@ -2053,8 +2053,8 @@ 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 { - let pre_cast_ty = cx.tables().expr_ty(cast_exp); - let cast_ty = cx.tables().expr_ty(expr); + 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 if cx.layout_of(pre_cast_ty).ok().map(|l| l.size) == cx.layout_of(cast_ty).ok().map(|l| l.size) { return None; @@ -2084,9 +2084,9 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> } fn node_as_const_fullint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { - let val = constant(cx, cx.tables(), expr)?.0; + let val = constant(cx, cx.typeck_results(), expr)?.0; if let Constant::Int(const_int) = val { - match cx.tables().expr_ty(expr).kind { + match cx.typeck_results().expr_ty(expr).kind { ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))), ty::Uint(_) => Some(FullInt::U(const_int)), _ => None, @@ -2472,7 +2472,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'a, 'tcx> { /// Looks for default-hasher-dependent constructors like `HashMap::new`. struct ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> { cx: &'a LateContext<'tcx>, - maybe_typeck_tables: Option<&'tcx TypeckTables<'tcx>>, + maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>, target: &'b ImplicitHasherType<'tcx>, suggestions: BTreeMap, } @@ -2481,7 +2481,7 @@ impl<'a, 'b, 'tcx> ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> { fn new(cx: &'a LateContext<'tcx>, target: &'b ImplicitHasherType<'tcx>) -> Self { Self { cx, - maybe_typeck_tables: cx.maybe_typeck_tables(), + maybe_typeck_results: cx.maybe_typeck_results(), target, suggestions: BTreeMap::new(), } @@ -2492,9 +2492,9 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't type Map = Map<'tcx>; fn visit_body(&mut self, body: &'tcx Body<'_>) { - let old_maybe_typeck_tables = self.maybe_typeck_tables.replace(self.cx.tcx.body_tables(body.id())); + let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body.id())); walk_body(self, body); - self.maybe_typeck_tables = old_maybe_typeck_tables; + self.maybe_typeck_results = old_maybe_typeck_results; } fn visit_expr(&mut self, e: &'tcx Expr<'_>) { @@ -2503,7 +2503,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 !TyS::same_type(self.target.ty(), self.maybe_typeck_tables.unwrap().expr_ty(e)) { + if !TyS::same_type(self.target.ty(), self.maybe_typeck_results.unwrap().expr_ty(e)) { return; } @@ -2589,7 +2589,7 @@ impl<'tcx> LateLintPass<'tcx> for RefToMut { if let TyKind::Ptr(MutTy { mutbl: Mutability::Mut, .. }) = t.kind; if let ExprKind::Cast(e, t) = &e.kind; if let TyKind::Ptr(MutTy { mutbl: Mutability::Not, .. }) = t.kind; - if let ty::Ref(..) = cx.tables().node_type(e.hir_id).kind; + if let ty::Ref(..) = cx.typeck_results().node_type(e.hir_id).kind; then { span_lint( cx, diff --git a/clippy_lints/src/unnamed_address.rs b/clippy_lints/src/unnamed_address.rs index 25d136e564d..28b393b9f11 100644 --- a/clippy_lints/src/unnamed_address.rs +++ b/clippy_lints/src/unnamed_address.rs @@ -65,14 +65,14 @@ impl LateLintPass<'_> for UnnamedAddress { } fn is_trait_ptr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - match cx.tables().expr_ty_adjusted(expr).kind { + match cx.typeck_results().expr_ty_adjusted(expr).kind { ty::RawPtr(ty::TypeAndMut { ty, .. }) => ty.is_trait(), _ => false, } } fn is_fn_def(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - matches!(cx.tables().expr_ty(expr).kind, ty::FnDef(..)) + matches!(cx.typeck_results().expr_ty(expr).kind, ty::FnDef(..)) } if_chain! { @@ -98,7 +98,7 @@ impl LateLintPass<'_> for UnnamedAddress { if match_def_path(cx, def_id, &paths::PTR_EQ) || match_def_path(cx, def_id, &paths::RC_PTR_EQ) || match_def_path(cx, def_id, &paths::ARC_PTR_EQ); - let ty_param = cx.tables().node_substs(func.hir_id).type_at(0); + let ty_param = cx.typeck_results().node_substs(func.hir_id).type_at(0); if ty_param.is_trait(); then { span_lint_and_help( @@ -115,8 +115,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.tables().expr_ty_adjusted(left).is_fn_ptr() && - cx.tables().expr_ty_adjusted(right).is_fn_ptr(); + if cx.typeck_results().expr_ty_adjusted(left).is_fn_ptr() && + 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/unnecessary_sort_by.rs b/clippy_lints/src/unnecessary_sort_by.rs index 91c1789a2ff..59993d25bb4 100644 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ b/clippy_lints/src/unnecessary_sort_by.rs @@ -176,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::match_type(cx, &cx.tables().expr_ty(vec), &paths::VEC); + if utils::match_type(cx, &cx.typeck_results().expr_ty(vec), &paths::VEC); 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 56ff62eca03..f2bbde28c2a 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -114,7 +114,7 @@ fn collect_unwrap_info<'tcx>( if_chain! { if let ExprKind::MethodCall(method_name, _, args, _) = &expr.kind; if let ExprKind::Path(QPath::Resolved(None, path)) = &args[0].kind; - let ty = cx.tables().expr_ty(&args[0]); + let ty = cx.typeck_results().expr_ty(&args[0]); let name = method_name.ident.as_str(); if is_relevant_option_call(cx, ty, &name) || is_relevant_result_call(cx, ty, &name); then { diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 69c0b092520..a48ad3185e9 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -63,8 +63,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { ExprKind::MethodCall(ref name, .., ref args, _) => { 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]); + let a = cx.typeck_results().expr_ty(e); + let b = cx.typeck_results().expr_ty(&args[0]); if TyS::same_type(a, b) { let sugg = snippet_with_macro_callsite(cx, args[0].span, "").to_string(); span_lint_and_sugg( @@ -79,8 +79,8 @@ impl<'tcx> LateLintPass<'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]); + let a = cx.typeck_results().expr_ty(e); + let b = cx.typeck_results().expr_ty(&args[0]); if TyS::same_type(a, b) { let sugg = snippet(cx, args[0].span, "").into_owned(); span_lint_and_sugg( @@ -96,8 +96,8 @@ 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.tables().expr_ty(e); - let b = cx.tables().expr_ty(&args[0]); + 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(); @@ -122,8 +122,8 @@ 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.tables().expr_ty(e); - let b = cx.tables().expr_ty(&args[0]); + let a = cx.typeck_results().expr_ty(e); + let b = cx.typeck_results().expr_ty(&args[0]); then { if_chain! { diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index eb7ac2447e4..f81a132c7e7 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -56,7 +56,7 @@ pub fn range<'a, 'tcx>(cx: &LateContext<'tcx>, expr: &'a hir::Expr<'_>) -> Optio Some(expr) } - let def_path = match cx.tables().expr_ty(expr).kind { + let def_path = match cx.typeck_results().expr_ty(expr).kind { ty::Adt(def, _) => cx.tcx.def_path(def.did), _ => return None, }; diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index 34341594c19..28fb6ed12a0 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -9,7 +9,7 @@ use rustc_hir::{ }; use rustc_lint::LateContext; use rustc_middle::ich::StableHashingContextProvider; -use rustc_middle::ty::TypeckTables; +use rustc_middle::ty::TypeckResults; use rustc_span::Symbol; use std::hash::Hash; @@ -22,7 +22,7 @@ use std::hash::Hash; pub struct SpanlessEq<'a, 'tcx> { /// Context used to evaluate constant expressions. cx: &'a LateContext<'tcx>, - maybe_typeck_tables: Option<&'tcx TypeckTables<'tcx>>, + maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>, /// If is true, never consider as equal expressions containing function /// calls. ignore_fn: bool, @@ -32,7 +32,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { pub fn new(cx: &'a LateContext<'tcx>) -> Self { Self { cx, - maybe_typeck_tables: cx.maybe_typeck_tables(), + maybe_typeck_results: cx.maybe_typeck_results(), ignore_fn: false, } } @@ -71,10 +71,10 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { return false; } - if let Some(tables) = self.maybe_typeck_tables { + if let Some(typeck_results) = self.maybe_typeck_results { if let (Some(l), Some(r)) = ( - constant_simple(self.cx, tables, left), - constant_simple(self.cx, tables, right), + constant_simple(self.cx, typeck_results, left), + constant_simple(self.cx, typeck_results, right), ) { if l == r { return true; @@ -137,9 +137,9 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { !self.ignore_fn && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args) }, (&ExprKind::Repeat(ref le, ref ll_id), &ExprKind::Repeat(ref re, ref rl_id)) => { - let mut celcx = constant_context(self.cx, self.cx.tcx.body_tables(ll_id.body)); + let mut celcx = constant_context(self.cx, self.cx.tcx.typeck_body(ll_id.body)); let ll = celcx.expr(&self.cx.tcx.hir().body(ll_id.body).value); - let mut celcx = constant_context(self.cx, self.cx.tcx.body_tables(rl_id.body)); + let mut celcx = constant_context(self.cx, self.cx.tcx.typeck_body(rl_id.body)); let rl = celcx.expr(&self.cx.tcx.hir().body(rl_id.body).value); self.eq_expr(le, re) && ll == rl @@ -272,18 +272,18 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { match (left, right) { (&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 old_maybe_typeck_tables = self.maybe_typeck_tables; + let old_maybe_typeck_results = self.maybe_typeck_results; - let mut celcx = constant_context(self.cx, self.cx.tcx.body_tables(ll_id.body)); - self.maybe_typeck_tables = Some(self.cx.tcx.body_tables(ll_id.body)); + let mut celcx = constant_context(self.cx, self.cx.tcx.typeck_body(ll_id.body)); + self.maybe_typeck_results = Some(self.cx.tcx.typeck_body(ll_id.body)); let ll = celcx.expr(&self.cx.tcx.hir().body(ll_id.body).value); - let mut celcx = constant_context(self.cx, self.cx.tcx.body_tables(rl_id.body)); - self.maybe_typeck_tables = Some(self.cx.tcx.body_tables(rl_id.body)); + let mut celcx = constant_context(self.cx, self.cx.tcx.typeck_body(rl_id.body)); + self.maybe_typeck_results = Some(self.cx.tcx.typeck_body(rl_id.body)); let rl = celcx.expr(&self.cx.tcx.hir().body(rl_id.body).value); let eq_ty = self.eq_ty(lt, rt); - self.maybe_typeck_tables = old_maybe_typeck_tables; + self.maybe_typeck_results = old_maybe_typeck_results; eq_ty && ll == rl }, (&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => { @@ -348,7 +348,7 @@ pub fn over(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) - pub struct SpanlessHash<'a, 'tcx> { /// Context used to evaluate constant expressions. cx: &'a LateContext<'tcx>, - maybe_typeck_tables: Option<&'tcx TypeckTables<'tcx>>, + maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>, s: StableHasher, } @@ -356,7 +356,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn new(cx: &'a LateContext<'tcx>) -> Self { Self { cx, - maybe_typeck_tables: cx.maybe_typeck_tables(), + maybe_typeck_results: cx.maybe_typeck_results(), s: StableHasher::new(), } } @@ -386,8 +386,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { #[allow(clippy::many_single_char_names, clippy::too_many_lines)] pub fn hash_expr(&mut self, e: &Expr<'_>) { let simple_const = self - .maybe_typeck_tables - .and_then(|tables| constant_simple(self.cx, tables, e)); + .maybe_typeck_results + .and_then(|typeck_results| constant_simple(self.cx, typeck_results, e)); // const hashing may result in the same hash as some unrelated node, so add a sort of // discriminant depending on which path we're choosing next @@ -458,7 +458,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { CaptureBy::Ref => 1, } .hash(&mut self.s); - // closures inherit TypeckTables + // closures inherit TypeckResults self.hash_expr(&self.cx.tcx.hir().body(eid).value); }, ExprKind::Field(ref e, ref f) => { @@ -602,7 +602,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_name(path.ident.name); }, } - // self.maybe_typeck_tables.unwrap().qpath_res(p, id).hash(&mut self.s); + // self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s); } pub fn hash_path(&mut self, p: &Path<'_>) { @@ -725,10 +725,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } pub fn hash_body(&mut self, body_id: BodyId) { - // swap out TypeckTables when hashing a body - let old_maybe_typeck_tables = self.maybe_typeck_tables.replace(self.cx.tcx.body_tables(body_id)); + // swap out TypeckResults when hashing a body + let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body_id)); self.hash_expr(&self.cx.tcx.hir().body(body_id).value); - self.maybe_typeck_tables = old_maybe_typeck_tables; + self.maybe_typeck_results = old_maybe_typeck_results; } fn hash_generic_args(&mut self, arg_list: &[GenericArg<'_>]) { diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index fbd103323e3..d8fa1fa278e 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -114,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for DeepCodeInspector { } match stmt.kind { hir::StmtKind::Local(ref local) => { - println!("local variable of type {}", cx.tables().node_type(local.hir_id)); + 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 { @@ -144,8 +144,12 @@ fn has_attr(sess: &Session, attrs: &[Attribute]) -> bool { fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { let ind = " ".repeat(indent); println!("{}+", ind); - println!("{}ty: {}", ind, cx.tables().expr_ty(expr)); - println!("{}adjustments: {:?}", ind, cx.tables().adjustments().get(expr.hir_id)); + println!("{}ty: {}", ind, cx.typeck_results().expr_ty(expr)); + println!( + "{}adjustments: {:?}", + ind, + cx.typeck_results().adjustments().get(expr.hir_id) + ); match expr.kind { hir::ExprKind::Box(ref e) => { println!("{}Box", ind); diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 38cb764adde..6c235679914 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -405,7 +405,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.tables().expr_ty(&args[0])); + let ty = walk_ptrs_ty(cx.typeck_results().expr_ty(&args[0])); if match_type(cx, ty, &paths::EARLY_CONTEXT) || match_type(cx, ty, &paths::LATE_CONTEXT); then { @@ -438,7 +438,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.tables().expr_ty(self_arg)); + let self_ty = walk_ptrs_ty(cx.typeck_results().expr_ty(self_arg)); 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 4b7a1c2b537..4b163fba528 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -144,7 +144,7 @@ pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symb /// Checks if the method call given in `expr` belongs to the given trait. 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 def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); let trt_id = cx.tcx.trait_of_item(def_id); trt_id.map_or(false, |trt_id| match_def_path(cx, trt_id, path)) } @@ -278,10 +278,8 @@ pub fn qpath_res(cx: &LateContext<'_>, qpath: &hir::QPath<'_>, id: hir::HirId) - match qpath { hir::QPath::Resolved(_, path) => path.res, hir::QPath::TypeRelative(..) => { - if cx.tcx.has_typeck_tables(id.owner.to_def_id()) { - cx.tcx - .typeck_tables_of(id.owner.to_def_id().expect_local()) - .qpath_res(qpath, id) + if cx.tcx.has_typeck_results(id.owner.to_def_id()) { + cx.tcx.typeck(id.owner.to_def_id().expect_local()).qpath_res(qpath, id) } else { Res::Err } @@ -772,7 +770,7 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool let parent_item = map.get_parent_item(e.hir_id); if let Some((Constant::Int(v), _)) = map .maybe_body_owned_by(parent_item) - .and_then(|body_id| constant(cx, cx.tcx.body_tables(body_id), e)) + .and_then(|body_id| constant(cx, cx.tcx.typeck_body(body_id), e)) { value == v } else { @@ -799,7 +797,7 @@ pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool { /// See `rustc_middle::ty::adjustment::Adjustment` and `rustc_typeck::check::coercion` for more /// information on adjustments and coercions. pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { - cx.tables().adjustments().get(e.hir_id).is_some() + cx.typeck_results().adjustments().get(e.hir_id).is_some() } /// Returns the pre-expansion span if is this comes from an expansion of the @@ -916,7 +914,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats.iter().map(|pat| &**pat)) }, PatKind::Slice(ref head, ref middle, ref tail) => { - match &cx.tables().node_type(pat.hir_id).kind { + match &cx.typeck_results().node_type(pat.hir_id).kind { ty::Slice(..) => { // [..] is the only irrefutable slice pattern. !head.is_empty() || middle.is_none() || !tail.is_empty() @@ -1299,7 +1297,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { None } }, - ExprKind::MethodCall(_, _, _, _) => cx.tables().type_dependent_def_id(expr.hir_id), + ExprKind::MethodCall(_, _, _, _) => cx.typeck_results().type_dependent_def_id(expr.hir_id), _ => None, }; @@ -1359,14 +1357,14 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool { /// Returns the `DefId` of the callee if the given expression is a function or method call. pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { match &expr.kind { - ExprKind::MethodCall(..) => cx.tables().type_dependent_def_id(expr.hir_id), + ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id), ExprKind::Call( Expr { kind: ExprKind::Path(qpath), .. }, .., - ) => cx.tables().qpath_res(qpath, expr.hir_id).opt_def_id(), + ) => cx.typeck_results().qpath_res(qpath, expr.hir_id).opt_def_id(), _ => None, } } diff --git a/clippy_lints/src/utils/usage.rs b/clippy_lints/src/utils/usage.rs index 53d3a241f58..4a64b935ac9 100644 --- a/clippy_lints/src/utils/usage.rs +++ b/clippy_lints/src/utils/usage.rs @@ -18,7 +18,14 @@ pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> }; let def_id = expr.hir_id.owner.to_def_id(); cx.tcx.infer_ctxt().enter(|infcx| { - ExprUseVisitor::new(&mut delegate, &infcx, def_id.expect_local(), cx.param_env, cx.tables()).walk_expr(expr); + ExprUseVisitor::new( + &mut delegate, + &infcx, + def_id.expect_local(), + cx.param_env, + cx.typeck_results(), + ) + .walk_expr(expr); }); if delegate.skip { diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index e1043c36e0a..f2e76442a19 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -37,7 +37,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // search for `&vec![_]` expressions where the adjusted type is `&[_]` if_chain! { - if let ty::Ref(_, ty, _) = cx.tables().expr_ty_adjusted(expr).kind; + 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, _, ref addressee) = expr.kind; if let Some(vec_args) = higher::vec_macro(cx, addressee); @@ -50,7 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { if_chain! { if let Some((_, arg, _)) = higher::for_loop(expr); if let Some(vec_args) = higher::vec_macro(cx, arg); - if is_copy(cx, vec_type(cx.tables().expr_ty_adjusted(arg))); + if is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(arg))); then { // report the error around the `vec!` not inside `:` let span = arg.span @@ -70,7 +70,7 @@ fn check_vec_macro<'tcx>(cx: &LateContext<'tcx>, vec_args: &higher::VecArgs<'tcx let mut applicability = Applicability::MachineApplicable; let snippet = match *vec_args { higher::VecArgs::Repeat(elem, len) => { - if constant(cx, cx.tables(), len).is_some() { + if constant(cx, cx.typeck_results(), len).is_some() { format!( "&[{}; {}]", snippet_with_applicability(cx, elem.span, "elem", &mut applicability), diff --git a/clippy_lints/src/vec_resize_to_zero.rs b/clippy_lints/src/vec_resize_to_zero.rs index cc5e21a7ca6..ad73a1ea1ac 100644 --- a/clippy_lints/src/vec_resize_to_zero.rs +++ b/clippy_lints/src/vec_resize_to_zero.rs @@ -32,7 +32,7 @@ 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 Some(method_def_id) = cx.tables().type_dependent_def_id(expr.hir_id); + 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; diff --git a/clippy_lints/src/verbose_file_reads.rs b/clippy_lints/src/verbose_file_reads.rs index b06fe36da63..32574d9d6c9 100644 --- a/clippy_lints/src/verbose_file_reads.rs +++ b/clippy_lints/src/verbose_file_reads.rs @@ -62,7 +62,7 @@ fn is_file_read_to_end<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> if let ExprKind::MethodCall(method_name, _, exprs, _) = expr.kind; if method_name.ident.as_str() == "read_to_end"; if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind; - let ty = cx.tables().expr_ty(&exprs[0]); + let ty = cx.typeck_results().expr_ty(&exprs[0]); if match_type(cx, ty, &paths::FILE); then { return true @@ -76,7 +76,7 @@ fn is_file_read_to_string<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) 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.tables().expr_ty(&exprs[0]); + let ty = cx.typeck_results().expr_ty(&exprs[0]); if match_type(cx, ty, &paths::FILE); then { return true diff --git a/clippy_lints/src/zero_div_zero.rs b/clippy_lints/src/zero_div_zero.rs index 1e011ea9cba..4b81a27632d 100644 --- a/clippy_lints/src/zero_div_zero.rs +++ b/clippy_lints/src/zero_div_zero.rs @@ -36,8 +36,8 @@ impl<'tcx> LateLintPass<'tcx> for ZeroDiv { // 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.tables(), left); - if let Some(rhs_value) = constant_simple(cx, cx.tables(), right); + 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 { diff --git a/doc/common_tools_writing_lints.md b/doc/common_tools_writing_lints.md index 412ff99314d..9dd4c8a5f7a 100644 --- a/doc/common_tools_writing_lints.md +++ b/doc/common_tools_writing_lints.md @@ -23,7 +23,7 @@ Sometimes you may want to retrieve the type `Ty` of an expression `Expr`, for ex - is it a primitive type? - does it implement a trait? -This operation is performed using the [`expr_ty()`][expr_ty] method from the [`TypeckTables`][TypeckTables] struct, +This operation is performed using the [`expr_ty()`][expr_ty] method from the [`TypeckResults`][TypeckResults] struct, that gives you access to the underlying structure [`TyS`][TyS]. Example of use: @@ -31,7 +31,7 @@ Example of use: impl LateLintPass<'_> for MyStructLint { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { // Get type of `expr` - let ty = cx.tables().expr_ty(expr); + let ty = cx.typeck_results().expr_ty(expr); // Match its kind to enter its type match ty.kind { ty::Adt(adt_def, _) if adt_def.is_struct() => println!("Our `expr` is a struct!"), @@ -41,14 +41,14 @@ impl LateLintPass<'_> for MyStructLint { } ``` -Similarly in [`TypeckTables`][TypeckTables] methods, you have the [`pat_ty()`][pat_ty] method +Similarly in [`TypeckResults`][TypeckResults] methods, you have the [`pat_ty()`][pat_ty] method to retrieve a type from a pattern. Two noticeable items here: - `cx` is the lint context [`LateContext`][LateContext]. The two most useful data structures in this context are `tcx` and `tables`, allowing us to jump to type definitions and other compilation stages such as HIR. -- `tables` is [`TypeckTables`][TypeckTables] and is created by type checking step, +- `tables` is [`TypeckResults`][TypeckResults] and is created by type checking step, it includes useful information such as types of expressions, ways to resolve methods and so on. # Checking if an expr is calling a specific method @@ -87,7 +87,7 @@ impl LateLintPass<'_> for MyStructLint { } // 2. Using type context `TyCtxt` - let ty = cx.tables().expr_ty(expr); + let ty = cx.typeck_results().expr_ty(expr); if cx.tcx.lang_items() // we are looking for the `DefId` of `Drop` trait in lang items .drop_trait() @@ -192,9 +192,9 @@ assert_eq!(differing_macro_contexts(x_is_some_span, x_unwrap_span), true); [TyS]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyS.html [TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html -[TypeckTables]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckTables.html -[expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckTables.html#method.expr_ty +[TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html +[expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.expr_ty [LateContext]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LateContext.html [TyCtxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html -[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckTables.html#method.pat_ty +[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckResults.html#method.pat_ty [paths]: ../clippy_lints/src/utils/paths.rs From e5105e82d31b254a81f38fbf38a8043ba41bee3a Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Fri, 17 Jul 2020 22:51:57 +0900 Subject: [PATCH 24/36] Fix typo --- clippy_lints/src/vec_resize_to_zero.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/vec_resize_to_zero.rs b/clippy_lints/src/vec_resize_to_zero.rs index cc5e21a7ca6..7f90aedf161 100644 --- a/clippy_lints/src/vec_resize_to_zero.rs +++ b/clippy_lints/src/vec_resize_to_zero.rs @@ -11,7 +11,7 @@ use rustc_ast::ast::LitKind; use rustc_hir as hir; declare_clippy_lint! { - /// **What it does:** Finds occurences 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. /// From 7c5d4a41459abeb40eea734efaf08657602815cb Mon Sep 17 00:00:00 2001 From: JarredAllen Date: Fri, 17 Jul 2020 09:27:43 -0700 Subject: [PATCH 25/36] Add test for correct behavior --- tests/ui/redundant_pattern_matching.fixed | 3 + tests/ui/redundant_pattern_matching.rs | 3 + tests/ui/redundant_pattern_matching.stderr | 68 ++++++++++++---------- 3 files changed, 43 insertions(+), 31 deletions(-) diff --git a/tests/ui/redundant_pattern_matching.fixed b/tests/ui/redundant_pattern_matching.fixed index ce8582d2b22..adbff8af8d9 100644 --- a/tests/ui/redundant_pattern_matching.fixed +++ b/tests/ui/redundant_pattern_matching.fixed @@ -11,6 +11,9 @@ )] fn main() { + let result: Result = Err(5); + if result.is_ok() {} + if Ok::(42).is_ok() {} if Err::(42).is_err() {} diff --git a/tests/ui/redundant_pattern_matching.rs b/tests/ui/redundant_pattern_matching.rs index a3a9aa40e3b..4c2870e7803 100644 --- a/tests/ui/redundant_pattern_matching.rs +++ b/tests/ui/redundant_pattern_matching.rs @@ -11,6 +11,9 @@ )] fn main() { + let result: Result = Err(5); + if let Ok(_) = &result {} + if let Ok(_) = Ok::(42) {} if let Err(_) = Err::(42) {} diff --git a/tests/ui/redundant_pattern_matching.stderr b/tests/ui/redundant_pattern_matching.stderr index 25d1476062e..d3c9ceaa3d7 100644 --- a/tests/ui/redundant_pattern_matching.stderr +++ b/tests/ui/redundant_pattern_matching.stderr @@ -1,73 +1,79 @@ error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:14:12 + --> $DIR/redundant_pattern_matching.rs:15:12 | -LL | if let Ok(_) = Ok::(42) {} - | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` +LL | if let Ok(_) = &result {} + | -------^^^^^---------- help: try this: `if result.is_ok()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` +error: redundant pattern matching, consider using `is_ok()` + --> $DIR/redundant_pattern_matching.rs:17:12 + | +LL | if let Ok(_) = Ok::(42) {} + | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` + error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:16:12 + --> $DIR/redundant_pattern_matching.rs:19:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:18:12 + --> $DIR/redundant_pattern_matching.rs:21: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.rs:20:12 + --> $DIR/redundant_pattern_matching.rs:23: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.rs:22:12 + --> $DIR/redundant_pattern_matching.rs:25: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.rs:28:15 + --> $DIR/redundant_pattern_matching.rs:31: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.rs:30:15 + --> $DIR/redundant_pattern_matching.rs:33: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.rs:32:15 + --> $DIR/redundant_pattern_matching.rs:35:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try this: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:34:15 + --> $DIR/redundant_pattern_matching.rs:37:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:36:15 + --> $DIR/redundant_pattern_matching.rs:39:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:39:15 + --> $DIR/redundant_pattern_matching.rs:42:15 | LL | while let Some(_) = v.pop() { | ----------^^^^^^^---------- help: try this: `while v.pop().is_some()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:55:5 + --> $DIR/redundant_pattern_matching.rs:58:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -76,7 +82,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:60:5 + --> $DIR/redundant_pattern_matching.rs:63:5 | LL | / match Ok::(42) { LL | | Ok(_) => false, @@ -85,7 +91,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_err()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:65:5 + --> $DIR/redundant_pattern_matching.rs:68:5 | LL | / match Err::(42) { LL | | Ok(_) => false, @@ -94,7 +100,7 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:70:5 + --> $DIR/redundant_pattern_matching.rs:73:5 | LL | / match Err::(42) { LL | | Ok(_) => true, @@ -103,7 +109,7 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_ok()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:75:5 + --> $DIR/redundant_pattern_matching.rs:78:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -112,7 +118,7 @@ LL | | }; | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:80:5 + --> $DIR/redundant_pattern_matching.rs:83:5 | LL | / match None::<()> { LL | | Some(_) => false, @@ -121,7 +127,7 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:85:13 + --> $DIR/redundant_pattern_matching.rs:88:13 | LL | let _ = match None::<()> { | _____________^ @@ -131,64 +137,64 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:90:20 + --> $DIR/redundant_pattern_matching.rs:93:20 | LL | let _ = if let Ok(_) = Ok::(4) { true } else { false }; | -------^^^^^--------------------- help: try this: `if Ok::(4).is_ok()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:93:20 + --> $DIR/redundant_pattern_matching.rs:96:20 | LL | let x = 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.rs:99:20 + --> $DIR/redundant_pattern_matching.rs:102: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.rs:101:19 + --> $DIR/redundant_pattern_matching.rs:104:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try this: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:103:19 + --> $DIR/redundant_pattern_matching.rs:106:19 | LL | } else if let Ok(_) = gen_res() { | -------^^^^^------------ help: try this: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:105:19 + --> $DIR/redundant_pattern_matching.rs:108:19 | LL | } else if let Err(_) = gen_res() { | -------^^^^^^------------ help: try this: `if gen_res().is_err()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:138:19 + --> $DIR/redundant_pattern_matching.rs:141:19 | LL | while let Some(_) = r#try!(result_opt()) {} | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:139:16 + --> $DIR/redundant_pattern_matching.rs:142:16 | LL | if let Some(_) = r#try!(result_opt()) {} | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:145:12 + --> $DIR/redundant_pattern_matching.rs:148:12 | LL | if let Some(_) = m!() {} | -------^^^^^^^------- help: try this: `if m!().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:146:15 + --> $DIR/redundant_pattern_matching.rs:149:15 | LL | while let Some(_) = m!() {} | ----------^^^^^^^------- help: try this: `while m!().is_some()` -error: aborting due to 28 previous errors +error: aborting due to 29 previous errors From e85b590936863e88da4ccd73af9f5da0787b9609 Mon Sep 17 00:00:00 2001 From: JarredAllen Date: Fri, 17 Jul 2020 10:40:01 -0700 Subject: [PATCH 26/36] Fix bug in lint --- clippy_lints/src/matches.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index bd474c20807..fe00a48adef 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1512,6 +1512,10 @@ mod redundant_pattern_match { } } + let result_expr = match &op.kind { + ExprKind::AddrOf(_, _, borrowed) => borrowed, + _ => op, + }; span_lint_and_then( cx, REDUNDANT_PATTERN_MATCHING, @@ -1524,7 +1528,7 @@ mod redundant_pattern_match { // while let ... = ... { ... } // ^^^ - let op_span = op.span.source_callsite(); + let op_span = result_expr.span.source_callsite(); // while let ... = ... { ... } // ^^^^^^^^^^^^^^^^^^^ @@ -1589,17 +1593,21 @@ mod redundant_pattern_match { }; if let Some(good_method) = found_good_method { + let span = expr.span.to(op.span); + let result_expr = match &op.kind { + ExprKind::AddrOf(_, _, borrowed) => borrowed, + _ => op, + }; span_lint_and_then( cx, REDUNDANT_PATTERN_MATCHING, expr.span, &format!("redundant pattern matching, consider using `{}`", good_method), |diag| { - let span = expr.span.to(op.span); diag.span_suggestion( span, "try this", - format!("{}.{}", snippet(cx, op.span, "_"), good_method), + format!("{}.{}", snippet(cx, result_expr.span, "_"), good_method), Applicability::MaybeIncorrect, // snippet ); }, From 3d3a13d8719893972e2146cde86672151e7d5476 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 17 Jul 2020 21:39:05 +0200 Subject: [PATCH 27/36] Fix sync fallout (fmt) --- clippy_lints/src/non_expressive_names.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 1d4772bb3d6..48ab98418e4 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -218,12 +218,16 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> { let mut split_at = None; match existing_name.len.cmp(&count) { Ordering::Greater => { - if existing_name.len - count != 1 || levenstein_not_1(&interned_name, &existing_name.interned.as_str()) { + if existing_name.len - count != 1 + || levenstein_not_1(&interned_name, &existing_name.interned.as_str()) + { continue; } }, Ordering::Less => { - if count - existing_name.len != 1 || levenstein_not_1(&existing_name.interned.as_str(), &interned_name) { + if count - existing_name.len != 1 + || levenstein_not_1(&existing_name.interned.as_str(), &interned_name) + { continue; } }, From c720d823e1e633cccfd24e1df76cc04a628e83b0 Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Tue, 14 Jul 2020 20:27:25 +0200 Subject: [PATCH 28/36] redundant_closure_call - don't lint when used more than once --- clippy_lints/src/misc_early.rs | 40 ++++++++++++++++++++------ tests/ui/redundant_closure_call.rs | 15 +++++++--- tests/ui/redundant_closure_call.stderr | 14 +++------ 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index b84a1a3fe24..125df226ceb 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -14,6 +14,7 @@ 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::source_map::Span; +use rustc_span::symbol::Ident; declare_clippy_lint! { /// **What it does:** Checks for structure field patterns bound to wildcards. @@ -493,6 +494,29 @@ impl EarlyLintPass for MiscEarlyLints { } fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) { + fn count_closure_usage(block: &Block, ident: &Ident) -> usize { + struct ClosureUsageCount<'ast> { + ident: &'ast Ident, + count: usize, + }; + impl<'ast> Visitor<'ast> for ClosureUsageCount<'ast> { + fn visit_expr(&mut self, expr: &'ast Expr) { + if_chain! { + if let ExprKind::Call(ref closure, _) = expr.kind; + if let ExprKind::Path(_, ref path) = closure.kind; + if self.ident == &path.segments[0].ident; + then { + self.count += 1; + } + } + walk_expr(self, expr); + } + } + let mut closure_usage_count = ClosureUsageCount { ident, count: 0 }; + closure_usage_count.visit_block(block); + closure_usage_count.count + } + for w in block.stmts.windows(2) { if_chain! { if let StmtKind::Local(ref local) = w[0].kind; @@ -503,15 +527,15 @@ impl EarlyLintPass for MiscEarlyLints { if let ExprKind::Assign(_, ref call, _) = second.kind; if let ExprKind::Call(ref closure, _) = call.kind; if let ExprKind::Path(_, ref path) = closure.kind; + if ident == path.segments[0].ident; + if count_closure_usage(block, &ident) == 1; then { - if ident == path.segments[0].ident { - span_lint( - cx, - REDUNDANT_CLOSURE_CALL, - second.span, - "Closure called just once immediately after it was declared", - ); - } + span_lint( + cx, + REDUNDANT_CLOSURE_CALL, + second.span, + "Closure called just once immediately after it was declared", + ); } } } diff --git a/tests/ui/redundant_closure_call.rs b/tests/ui/redundant_closure_call.rs index bacd67db7c3..0f2ba4a075d 100644 --- a/tests/ui/redundant_closure_call.rs +++ b/tests/ui/redundant_closure_call.rs @@ -8,14 +8,21 @@ fn main() { k = (|a, b| a * b)(1, 5); - let closure = || 32; - i = closure(); - + // don't lint here, the closure is used more than once let closure = |i| i + 1; i = closure(3); - i = closure(4); + // lint here + let redun_closure = || 1; + i = redun_closure(); + + // the lint is applicable here but the lint doesn't support redefinition + let redefined_closure = || 1; + i = redefined_closure(); + let redefined_closure = || 2; + i = redefined_closure(); + #[allow(clippy::needless_return)] (|| return 2)(); (|| -> Option { None? })(); diff --git a/tests/ui/redundant_closure_call.stderr b/tests/ui/redundant_closure_call.stderr index 68c1416bb6b..d5e0664319b 100644 --- a/tests/ui/redundant_closure_call.stderr +++ b/tests/ui/redundant_closure_call.stderr @@ -1,17 +1,11 @@ error: Closure called just once immediately after it was declared - --> $DIR/redundant_closure_call.rs:12:5 + --> $DIR/redundant_closure_call.rs:18:5 | -LL | i = closure(); - | ^^^^^^^^^^^^^ +LL | i = redun_closure(); + | ^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::redundant-closure-call` implied by `-D warnings` -error: Closure called just once immediately after it was declared - --> $DIR/redundant_closure_call.rs:15:5 - | -LL | i = closure(3); - | ^^^^^^^^^^^^^^ - error: Try not to call a closure in the expression where it is declared. --> $DIR/redundant_closure_call.rs:7:17 | @@ -24,5 +18,5 @@ error: Try not to call a closure in the expression where it is declared. LL | k = (|a, b| a * b)(1, 5); | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors From 0fecaf1abcbe8d4ba1a9c532b69aab6fab3097c8 Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Sun, 19 Jul 2020 00:33:54 +0200 Subject: [PATCH 29/36] redundant_closure_call - extract lint from misc_early.rs, adapt to LatePass --- clippy_lints/src/lib.rs | 9 +- clippy_lints/src/misc_early.rs | 132 +-------------- clippy_lints/src/redundant_closure_call.rs | 151 ++++++++++++++++++ src/lintlist/mod.rs | 2 +- tests/ui/redundant_closure_call_early.rs | 19 +++ ...rr => redundant_closure_call_early.stderr} | 18 +-- ...call.rs => redundant_closure_call_late.rs} | 8 - tests/ui/redundant_closure_call_late.stderr | 10 ++ 8 files changed, 197 insertions(+), 152 deletions(-) create mode 100644 clippy_lints/src/redundant_closure_call.rs create mode 100644 tests/ui/redundant_closure_call_early.rs rename tests/ui/{redundant_closure_call.stderr => redundant_closure_call_early.stderr} (56%) rename tests/ui/{redundant_closure_call.rs => redundant_closure_call_late.rs} (72%) create mode 100644 tests/ui/redundant_closure_call_late.stderr diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 823afdfd289..f371942dbee 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -276,6 +276,7 @@ mod ptr_offset_with_cast; mod question_mark; mod ranges; mod redundant_clone; +mod redundant_closure_call; mod redundant_field_names; mod redundant_pub_crate; mod redundant_static_lifetimes; @@ -702,7 +703,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &misc_early::DOUBLE_NEG, &misc_early::DUPLICATE_UNDERSCORE_ARGUMENT, &misc_early::MIXED_CASE_HEX_LITERALS, - &misc_early::REDUNDANT_CLOSURE_CALL, &misc_early::REDUNDANT_PATTERN, &misc_early::UNNEEDED_FIELD_PATTERN, &misc_early::UNNEEDED_WILDCARD_PATTERN, @@ -759,6 +759,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &ranges::RANGE_ZIP_WITH_LEN, &ranges::REVERSED_EMPTY_RANGES, &redundant_clone::REDUNDANT_CLONE, + &redundant_closure_call::REDUNDANT_CLOSURE_CALL, &redundant_field_names::REDUNDANT_FIELD_NAMES, &redundant_pub_crate::REDUNDANT_PUB_CRATE, &redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES, @@ -1018,6 +1019,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box int_plus_one::IntPlusOne); store.register_early_pass(|| box formatting::Formatting); store.register_early_pass(|| box misc_early::MiscEarlyLints); + store.register_early_pass(|| box redundant_closure_call::RedundantClosureCall); + store.register_late_pass(|| box redundant_closure_call::RedundantClosureCall); store.register_early_pass(|| box returns::Return); store.register_late_pass(|| box let_and_return::LetReturn); store.register_early_pass(|| box collapsible_if::CollapsibleIf); @@ -1359,7 +1362,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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_CLOSURE_CALL), LintId::of(&misc_early::REDUNDANT_PATTERN), LintId::of(&misc_early::UNNEEDED_WILDCARD_PATTERN), LintId::of(&misc_early::ZERO_PREFIXED_LITERAL), @@ -1393,6 +1395,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), LintId::of(&reference::DEREF_ADDROF), @@ -1593,7 +1596,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::UNNECESSARY_FILTER_MAP), LintId::of(&methods::USELESS_ASREF), LintId::of(&misc::SHORT_CIRCUIT_STATEMENT), - LintId::of(&misc_early::REDUNDANT_CLOSURE_CALL), LintId::of(&misc_early::UNNEEDED_WILDCARD_PATTERN), LintId::of(&misc_early::ZERO_PREFIXED_LITERAL), LintId::of(&needless_bool::BOOL_COMPARISON), @@ -1608,6 +1610,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: 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(&reference::DEREF_ADDROF), LintId::of(&reference::REF_IN_DEREF), LintId::of(&repeat_once::REPEAT_ONCE), diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index 125df226ceb..29aba7c1218 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -1,20 +1,15 @@ -use crate::utils::{ - constants, snippet_opt, snippet_with_applicability, span_lint, span_lint_and_help, span_lint_and_sugg, - span_lint_and_then, -}; -use if_chain::if_chain; +use crate::utils::{constants, snippet_opt, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use rustc_ast::ast::{ - BindingMode, Block, Expr, ExprKind, GenericParamKind, Generics, Lit, LitFloatType, LitIntType, LitKind, Mutability, - NodeId, Pat, PatKind, StmtKind, UnOp, + BindingMode, Expr, ExprKind, GenericParamKind, Generics, Lit, LitFloatType, LitIntType, LitKind, Mutability, + NodeId, Pat, PatKind, UnOp, }; -use rustc_ast::visit::{walk_expr, FnKind, Visitor}; +use rustc_ast::visit::FnKind; use rustc_data_structures::fx::FxHashMap; 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::source_map::Span; -use rustc_span::symbol::Ident; declare_clippy_lint! { /// **What it does:** Checks for structure field patterns bound to wildcards. @@ -71,28 +66,6 @@ declare_clippy_lint! { "function arguments having names which only differ by an underscore" } -declare_clippy_lint! { - /// **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 - /// complexity. - /// - /// **Known problems:** None. - /// - /// **Example:** - /// ```rust,ignore - /// // Bad - /// let a = (|| 42)() - /// - /// // Good - /// let a = 42 - /// ``` - pub REDUNDANT_CLOSURE_CALL, - complexity, - "throwaway closures called in the expression they are defined" -} - declare_clippy_lint! { /// **What it does:** Detects expressions of the form `--x`. /// @@ -279,7 +252,6 @@ declare_clippy_lint! { declare_lint_pass!(MiscEarlyLints => [ UNNEEDED_FIELD_PATTERN, DUPLICATE_UNDERSCORE_ARGUMENT, - REDUNDANT_CLOSURE_CALL, DOUBLE_NEG, MIXED_CASE_HEX_LITERALS, UNSEPARATED_LITERAL_SUFFIX, @@ -289,30 +261,6 @@ declare_lint_pass!(MiscEarlyLints => [ UNNEEDED_WILDCARD_PATTERN, ]); -// Used to find `return` statements or equivalents e.g., `?` -struct ReturnVisitor { - found_return: bool, -} - -impl ReturnVisitor { - #[must_use] - fn new() -> Self { - Self { found_return: false } - } -} - -impl<'ast> Visitor<'ast> for ReturnVisitor { - fn visit_expr(&mut self, ex: &'ast Expr) { - if let ExprKind::Ret(_) = ex.kind { - self.found_return = true; - } else if let ExprKind::Try(_) = ex.kind { - self.found_return = true; - } - - walk_expr(self, ex) - } -} - impl EarlyLintPass for MiscEarlyLints { fn check_generics(&mut self, cx: &EarlyContext<'_>, gen: &Generics) { for param in &gen.params { @@ -454,30 +402,6 @@ impl EarlyLintPass for MiscEarlyLints { return; } match expr.kind { - ExprKind::Call(ref paren, _) => { - if let ExprKind::Paren(ref closure) = paren.kind { - if let ExprKind::Closure(_, _, _, ref decl, ref block, _) = closure.kind { - let mut visitor = ReturnVisitor::new(); - visitor.visit_expr(block); - if !visitor.found_return { - span_lint_and_then( - cx, - REDUNDANT_CLOSURE_CALL, - expr.span, - "Try not to call a closure in the expression where it is declared.", - |diag| { - if decl.inputs.is_empty() { - let mut app = Applicability::MachineApplicable; - let hint = - snippet_with_applicability(cx, block.span, "..", &mut app).into_owned(); - diag.span_suggestion(expr.span, "Try doing something like: ", hint, app); - } - }, - ); - } - } - } - }, ExprKind::Unary(UnOp::Neg, ref inner) => { if let ExprKind::Unary(UnOp::Neg, _) = inner.kind { span_lint( @@ -492,54 +416,6 @@ impl EarlyLintPass for MiscEarlyLints { _ => (), } } - - fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) { - fn count_closure_usage(block: &Block, ident: &Ident) -> usize { - struct ClosureUsageCount<'ast> { - ident: &'ast Ident, - count: usize, - }; - impl<'ast> Visitor<'ast> for ClosureUsageCount<'ast> { - fn visit_expr(&mut self, expr: &'ast Expr) { - if_chain! { - if let ExprKind::Call(ref closure, _) = expr.kind; - if let ExprKind::Path(_, ref path) = closure.kind; - if self.ident == &path.segments[0].ident; - then { - self.count += 1; - } - } - walk_expr(self, expr); - } - } - let mut closure_usage_count = ClosureUsageCount { ident, count: 0 }; - closure_usage_count.visit_block(block); - closure_usage_count.count - } - - for w in block.stmts.windows(2) { - if_chain! { - if let StmtKind::Local(ref local) = w[0].kind; - if let Option::Some(ref t) = local.init; - if let ExprKind::Closure(..) = t.kind; - if let PatKind::Ident(_, ident, _) = local.pat.kind; - if let StmtKind::Semi(ref second) = w[1].kind; - if let ExprKind::Assign(_, ref call, _) = second.kind; - if let ExprKind::Call(ref closure, _) = call.kind; - if let ExprKind::Path(_, ref path) = closure.kind; - if ident == path.segments[0].ident; - if count_closure_usage(block, &ident) == 1; - then { - span_lint( - cx, - REDUNDANT_CLOSURE_CALL, - second.span, - "Closure called just once immediately after it was declared", - ); - } - } - } - } } impl MiscEarlyLints { diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs new file mode 100644 index 00000000000..391d70af159 --- /dev/null +++ b/clippy_lints/src/redundant_closure_call.rs @@ -0,0 +1,151 @@ +use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_then}; +use if_chain::if_chain; +use rustc_ast::ast; +use rustc_ast::visit as ast_visit; +use rustc_ast::visit::Visitor as AstVisitor; +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_lint::{EarlyContext, EarlyLintPass, 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::symbol::Ident; + +declare_clippy_lint! { + /// **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 + /// complexity. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust,ignore + /// // Bad + /// let a = (|| 42)() + /// + /// // Good + /// let a = 42 + /// ``` + pub REDUNDANT_CLOSURE_CALL, + complexity, + "throwaway closures called in the expression they are defined" +} + +declare_lint_pass!(RedundantClosureCall => [REDUNDANT_CLOSURE_CALL]); + +// Used to find `return` statements or equivalents e.g., `?` +struct ReturnVisitor { + found_return: bool, +} + +impl ReturnVisitor { + #[must_use] + fn new() -> Self { + Self { found_return: false } + } +} + +impl<'ast> ast_visit::Visitor<'ast> for ReturnVisitor { + fn visit_expr(&mut self, ex: &'ast ast::Expr) { + if let ast::ExprKind::Ret(_) = ex.kind { + self.found_return = true; + } else if let ast::ExprKind::Try(_) = ex.kind { + self.found_return = true; + } + + ast_visit::walk_expr(self, ex) + } +} + +impl EarlyLintPass for RedundantClosureCall { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { + if in_external_macro(cx.sess(), expr.span) { + return; + } + if_chain! { + if let ast::ExprKind::Call(ref paren, _) = expr.kind; + if let ast::ExprKind::Paren(ref closure) = paren.kind; + if let ast::ExprKind::Closure(_, _, _, ref decl, ref block, _) = closure.kind; + then { + let mut visitor = ReturnVisitor::new(); + visitor.visit_expr(block); + if !visitor.found_return { + span_lint_and_then( + cx, + REDUNDANT_CLOSURE_CALL, + expr.span, + "Try not to call a closure in the expression where it is declared.", + |diag| { + if decl.inputs.is_empty() { + let mut app = Applicability::MachineApplicable; + let hint = + snippet_with_applicability(cx, block.span, "..", &mut app).into_owned(); + diag.span_suggestion(expr.span, "Try doing something like: ", hint, app); + } + }, + ); + } + } + } + } +} + +impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { + fn count_closure_usage<'tcx>(block: &'tcx hir::Block<'_>, ident: &'tcx Ident) -> usize { + struct ClosureUsageCount<'tcx> { + ident: &'tcx Ident, + count: usize, + }; + impl<'tcx> hir_visit::Visitor<'tcx> for ClosureUsageCount<'tcx> { + type Map = Map<'tcx>; + + 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 self.ident == &path.segments[0].ident; + then { + self.count += 1; + } + } + hir_visit::walk_expr(self, expr); + } + + fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap { + hir_visit::NestedVisitorMap::None + } + }; + let mut closure_usage_count = ClosureUsageCount { ident, count: 0 }; + closure_usage_count.visit_block(block); + closure_usage_count.count + } + + 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::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 ident == path.segments[0].ident; + if count_closure_usage(block, &ident) == 1; + then { + span_lint( + cx, + REDUNDANT_CLOSURE_CALL, + second.span, + "Closure called just once immediately after it was declared", + ); + } + } + } + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 96b004904aa..1879aae77fb 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1835,7 +1835,7 @@ pub static ref ALL_LINTS: Vec = vec![ group: "complexity", desc: "throwaway closures called in the expression they are defined", deprecation: None, - module: "misc_early", + module: "redundant_closure_call", }, Lint { name: "redundant_closure_for_method_calls", diff --git a/tests/ui/redundant_closure_call_early.rs b/tests/ui/redundant_closure_call_early.rs new file mode 100644 index 00000000000..3dd365620cc --- /dev/null +++ b/tests/ui/redundant_closure_call_early.rs @@ -0,0 +1,19 @@ +// non rustfixable, see redundant_closure_call_fixable.rs + +#![warn(clippy::redundant_closure_call)] + +fn main() { + let mut i = 1; + + // lint here + let mut k = (|m| m + 1)(i); + + // lint here + k = (|a, b| a * b)(1, 5); + + // don't lint these + #[allow(clippy::needless_return)] + (|| return 2)(); + (|| -> Option { None? })(); + (|| -> Result { Err(2)? })(); +} diff --git a/tests/ui/redundant_closure_call.stderr b/tests/ui/redundant_closure_call_early.stderr similarity index 56% rename from tests/ui/redundant_closure_call.stderr rename to tests/ui/redundant_closure_call_early.stderr index d5e0664319b..0ac97ae25d0 100644 --- a/tests/ui/redundant_closure_call.stderr +++ b/tests/ui/redundant_closure_call_early.stderr @@ -1,22 +1,16 @@ -error: Closure called just once immediately after it was declared - --> $DIR/redundant_closure_call.rs:18:5 +error: Try not to call a closure in the expression where it is declared. + --> $DIR/redundant_closure_call_early.rs:9:17 | -LL | i = redun_closure(); - | ^^^^^^^^^^^^^^^^^^^ +LL | let mut k = (|m| m + 1)(i); + | ^^^^^^^^^^^^^^ | = note: `-D clippy::redundant-closure-call` implied by `-D warnings` error: Try not to call a closure in the expression where it is declared. - --> $DIR/redundant_closure_call.rs:7:17 - | -LL | let mut k = (|m| m + 1)(i); - | ^^^^^^^^^^^^^^ - -error: Try not to call a closure in the expression where it is declared. - --> $DIR/redundant_closure_call.rs:9:9 + --> $DIR/redundant_closure_call_early.rs:12:9 | LL | k = (|a, b| a * b)(1, 5); | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/redundant_closure_call.rs b/tests/ui/redundant_closure_call_late.rs similarity index 72% rename from tests/ui/redundant_closure_call.rs rename to tests/ui/redundant_closure_call_late.rs index 0f2ba4a075d..21ee58e5b44 100644 --- a/tests/ui/redundant_closure_call.rs +++ b/tests/ui/redundant_closure_call_late.rs @@ -4,9 +4,6 @@ fn main() { let mut i = 1; - let mut k = (|m| m + 1)(i); - - k = (|a, b| a * b)(1, 5); // don't lint here, the closure is used more than once let closure = |i| i + 1; @@ -22,9 +19,4 @@ fn main() { i = redefined_closure(); let redefined_closure = || 2; i = redefined_closure(); - - #[allow(clippy::needless_return)] - (|| return 2)(); - (|| -> Option { None? })(); - (|| -> Result { Err(2)? })(); } diff --git a/tests/ui/redundant_closure_call_late.stderr b/tests/ui/redundant_closure_call_late.stderr new file mode 100644 index 00000000000..0aebc3c419e --- /dev/null +++ b/tests/ui/redundant_closure_call_late.stderr @@ -0,0 +1,10 @@ +error: Closure called just once immediately after it was declared + --> $DIR/redundant_closure_call_late.rs:15:5 + | +LL | i = redun_closure(); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::redundant-closure-call` implied by `-D warnings` + +error: aborting due to previous error + From 9603d9652b9d172842c77f566121437768bc962f Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Sun, 19 Jul 2020 11:47:32 +0200 Subject: [PATCH 30/36] redundant_closure_call - add support for shadowed closures --- clippy_lints/src/redundant_closure_call.rs | 12 ++++++------ tests/ui/redundant_closure_call_late.rs | 15 ++++++++++----- tests/ui/redundant_closure_call_late.stderr | 14 +++++++++++++- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index 391d70af159..9477e79f567 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -11,7 +11,6 @@ use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintCon 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::symbol::Ident; declare_clippy_lint! { /// **What it does:** Detects closures called in the same expression where they @@ -96,9 +95,9 @@ 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<'tcx>(block: &'tcx hir::Block<'_>, ident: &'tcx Ident) -> usize { + fn count_closure_usage<'tcx>(block: &'tcx hir::Block<'_>, path: &'tcx hir::Path<'tcx>) -> usize { struct ClosureUsageCount<'tcx> { - ident: &'tcx Ident, + path: &'tcx hir::Path<'tcx>, count: usize, }; impl<'tcx> hir_visit::Visitor<'tcx> for ClosureUsageCount<'tcx> { @@ -108,7 +107,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.ident == &path.segments[0].ident; + if self.path.segments[0].ident == path.segments[0].ident + && self.path.res == path.res; then { self.count += 1; } @@ -120,7 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { hir_visit::NestedVisitorMap::None } }; - let mut closure_usage_count = ClosureUsageCount { ident, count: 0 }; + let mut closure_usage_count = ClosureUsageCount { path, count: 0 }; closure_usage_count.visit_block(block); closure_usage_count.count } @@ -136,7 +136,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { if let hir::ExprKind::Call(ref closure, _) = call.kind; if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = closure.kind; if ident == path.segments[0].ident; - if count_closure_usage(block, &ident) == 1; + if count_closure_usage(block, path) == 1; then { span_lint( cx, diff --git a/tests/ui/redundant_closure_call_late.rs b/tests/ui/redundant_closure_call_late.rs index 21ee58e5b44..e29a1dce0c7 100644 --- a/tests/ui/redundant_closure_call_late.rs +++ b/tests/ui/redundant_closure_call_late.rs @@ -14,9 +14,14 @@ fn main() { let redun_closure = || 1; i = redun_closure(); - // the lint is applicable here but the lint doesn't support redefinition - let redefined_closure = || 1; - i = redefined_closure(); - let redefined_closure = || 2; - i = redefined_closure(); + // shadowed closures are supported, lint here + let shadowed_closure = || 1; + i = shadowed_closure(); + let shadowed_closure = || 2; + i = shadowed_closure(); + + // don't lint here + let shadowed_closure = || 2; + i = shadowed_closure(); + i = shadowed_closure(); } diff --git a/tests/ui/redundant_closure_call_late.stderr b/tests/ui/redundant_closure_call_late.stderr index 0aebc3c419e..0e000fee85a 100644 --- a/tests/ui/redundant_closure_call_late.stderr +++ b/tests/ui/redundant_closure_call_late.stderr @@ -6,5 +6,17 @@ LL | i = redun_closure(); | = note: `-D clippy::redundant-closure-call` implied by `-D warnings` -error: aborting due to previous error +error: Closure called just once immediately after it was declared + --> $DIR/redundant_closure_call_late.rs:19:5 + | +LL | i = shadowed_closure(); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: Closure called just once immediately after it was declared + --> $DIR/redundant_closure_call_late.rs:21:5 + | +LL | i = shadowed_closure(); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors From 1ac8b85c9fd38ff0a14061cae0b4d31e9bfafd56 Mon Sep 17 00:00:00 2001 From: Tim Nielens Date: Mon, 20 Jul 2020 00:36:31 +0200 Subject: [PATCH 31/36] redundant_closure_call - pr review --- clippy_lints/src/redundant_closure_call.rs | 8 ++++---- tests/ui/redundant_closure_call_early.stderr | 4 ++-- tests/ui/redundant_closure_call_fixable.stderr | 4 ++-- tests/ui/redundant_closure_call_late.stderr | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index 9477e79f567..8aa478ea2d6 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -77,13 +77,13 @@ impl EarlyLintPass for RedundantClosureCall { cx, REDUNDANT_CLOSURE_CALL, expr.span, - "Try not to call a closure in the expression where it is declared.", + "try not to call a closure in the expression where it is declared.", |diag| { if decl.inputs.is_empty() { let mut app = Applicability::MachineApplicable; let hint = snippet_with_applicability(cx, block.span, "..", &mut app).into_owned(); - diag.span_suggestion(expr.span, "Try doing something like: ", hint, app); + diag.span_suggestion(expr.span, "try doing something like", hint, app); } }, ); @@ -136,13 +136,13 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { if let hir::ExprKind::Call(ref closure, _) = call.kind; if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = closure.kind; if ident == path.segments[0].ident; - if count_closure_usage(block, path) == 1; + if count_closure_usage(block, path) == 1; then { span_lint( cx, REDUNDANT_CLOSURE_CALL, second.span, - "Closure called just once immediately after it was declared", + "closure called just once immediately after it was declared", ); } } diff --git a/tests/ui/redundant_closure_call_early.stderr b/tests/ui/redundant_closure_call_early.stderr index 0ac97ae25d0..79f27663461 100644 --- a/tests/ui/redundant_closure_call_early.stderr +++ b/tests/ui/redundant_closure_call_early.stderr @@ -1,4 +1,4 @@ -error: Try not to call a closure in the expression where it is declared. +error: try not to call a closure in the expression where it is declared. --> $DIR/redundant_closure_call_early.rs:9:17 | LL | let mut k = (|m| m + 1)(i); @@ -6,7 +6,7 @@ LL | let mut k = (|m| m + 1)(i); | = note: `-D clippy::redundant-closure-call` implied by `-D warnings` -error: Try not to call a closure in the expression where it is declared. +error: try not to call a closure in the expression where it is declared. --> $DIR/redundant_closure_call_early.rs:12:9 | LL | k = (|a, b| a * b)(1, 5); diff --git a/tests/ui/redundant_closure_call_fixable.stderr b/tests/ui/redundant_closure_call_fixable.stderr index e7737f9dd85..644161d9f5d 100644 --- a/tests/ui/redundant_closure_call_fixable.stderr +++ b/tests/ui/redundant_closure_call_fixable.stderr @@ -1,8 +1,8 @@ -error: Try not to call a closure in the expression where it is declared. +error: try not to call a closure in the expression where it is declared. --> $DIR/redundant_closure_call_fixable.rs:7:13 | LL | let a = (|| 42)(); - | ^^^^^^^^^ help: Try doing something like: : `42` + | ^^^^^^^^^ help: try doing something like: `42` | = note: `-D clippy::redundant-closure-call` implied by `-D warnings` diff --git a/tests/ui/redundant_closure_call_late.stderr b/tests/ui/redundant_closure_call_late.stderr index 0e000fee85a..7c8865f1bd3 100644 --- a/tests/ui/redundant_closure_call_late.stderr +++ b/tests/ui/redundant_closure_call_late.stderr @@ -1,4 +1,4 @@ -error: Closure called just once immediately after it was declared +error: closure called just once immediately after it was declared --> $DIR/redundant_closure_call_late.rs:15:5 | LL | i = redun_closure(); @@ -6,13 +6,13 @@ LL | i = redun_closure(); | = note: `-D clippy::redundant-closure-call` implied by `-D warnings` -error: Closure called just once immediately after it was declared +error: closure called just once immediately after it was declared --> $DIR/redundant_closure_call_late.rs:19:5 | LL | i = shadowed_closure(); | ^^^^^^^^^^^^^^^^^^^^^^ -error: Closure called just once immediately after it was declared +error: closure called just once immediately after it was declared --> $DIR/redundant_closure_call_late.rs:21:5 | LL | i = shadowed_closure(); From a5cdd4aeb11fad6b0bf73d342398700a27c4484b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Mon, 20 Jul 2020 00:00:00 +0000 Subject: [PATCH 32/36] Ignore not really redundant clones of ManuallyDrop "Redundant" clones of `ManuallyDrop` are sometimes used for the side effect of invoking the clone, without running the drop implementation of the inner type. In other words, they aren't really redundant. For example, futures-rs crate: ```rust #[allow(clippy::redundant_clone)] // The clone here isn't actually redundant. unsafe fn increase_refcount(data: *const ()) { // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop let arc = mem::ManuallyDrop::new(Arc::::from_raw(data as *const T)); // Now increase refcount, but don't drop new refcount either let _arc_clone: mem::ManuallyDrop<_> = arc.clone(); } ``` Ignore redundant clone lint for ManuallyDrop. --- clippy_lints/src/redundant_clone.rs | 6 +++++ clippy_lints/src/utils/paths.rs | 1 + tests/ui/redundant_clone.fixed | 15 ++++++++++++ tests/ui/redundant_clone.rs | 15 ++++++++++++ tests/ui/redundant_clone.stderr | 38 ++++++++++++++--------------- 5 files changed, 56 insertions(+), 19 deletions(-) diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index fda7480194d..7932be0d4b1 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -124,6 +124,12 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { continue; } + if let ty::Adt(ref def, _) = arg_ty.kind { + if match_def_path(cx, def.did, &paths::MEM_MANUALLY_DROP) { + continue; + } + } + // `{ cloned = &arg; clone(move cloned); }` or `{ cloned = &arg; to_path_buf(cloned); }` let (cloned, cannot_move_out) = unwrap_or_continue!(find_stmt_assigns_to(cx, mir, arg, from_borrow, bb)); diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 4c3462802e9..a515ee29c82 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -59,6 +59,7 @@ pub const LINKED_LIST: [&str; 4] = ["alloc", "collections", "linked_list", "Link pub const LINT: [&str; 3] = ["rustc_session", "lint", "Lint"]; pub const MEM_DISCRIMINANT: [&str; 3] = ["core", "mem", "discriminant"]; pub const MEM_FORGET: [&str; 3] = ["core", "mem", "forget"]; +pub const MEM_MANUALLY_DROP: [&str; 4] = ["core", "mem", "manually_drop", "ManuallyDrop"]; pub const MEM_MAYBEUNINIT: [&str; 4] = ["core", "mem", "maybe_uninit", "MaybeUninit"]; pub const MEM_MAYBEUNINIT_UNINIT: [&str; 5] = ["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]; pub const MEM_REPLACE: [&str; 3] = ["core", "mem", "replace"]; diff --git a/tests/ui/redundant_clone.fixed b/tests/ui/redundant_clone.fixed index 764c10a6d39..cdeefda4c23 100644 --- a/tests/ui/redundant_clone.fixed +++ b/tests/ui/redundant_clone.fixed @@ -52,6 +52,7 @@ fn main() { borrower_propagation(); not_consumed(); issue_5405(); + manually_drop(); } #[derive(Clone)] @@ -170,3 +171,17 @@ fn issue_5405() { let c: [usize; 2] = [2, 3]; let _d: usize = c[1].clone(); } + +fn manually_drop() { + use std::mem::ManuallyDrop; + use std::sync::Arc; + + let a = ManuallyDrop::new(Arc::new("Hello!".to_owned())); + let _ = a.clone(); // OK + + let p: *const String = Arc::into_raw(ManuallyDrop::into_inner(a)); + unsafe { + Arc::from_raw(p); + Arc::from_raw(p); + } +} diff --git a/tests/ui/redundant_clone.rs b/tests/ui/redundant_clone.rs index 839747b131d..acb7ffb305f 100644 --- a/tests/ui/redundant_clone.rs +++ b/tests/ui/redundant_clone.rs @@ -52,6 +52,7 @@ fn main() { borrower_propagation(); not_consumed(); issue_5405(); + manually_drop(); } #[derive(Clone)] @@ -170,3 +171,17 @@ fn issue_5405() { let c: [usize; 2] = [2, 3]; let _d: usize = c[1].clone(); } + +fn manually_drop() { + use std::mem::ManuallyDrop; + use std::sync::Arc; + + let a = ManuallyDrop::new(Arc::new("Hello!".to_owned())); + let _ = a.clone(); // OK + + let p: *const String = Arc::into_raw(ManuallyDrop::into_inner(a)); + unsafe { + Arc::from_raw(p); + Arc::from_raw(p); + } +} diff --git a/tests/ui/redundant_clone.stderr b/tests/ui/redundant_clone.stderr index eced198283c..89b39254299 100644 --- a/tests/ui/redundant_clone.stderr +++ b/tests/ui/redundant_clone.stderr @@ -108,61 +108,61 @@ LL | let _t = tup.0.clone(); | ^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:61:22 + --> $DIR/redundant_clone.rs:62:22 | LL | (a.clone(), a.clone()) | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:61:21 + --> $DIR/redundant_clone.rs:62:21 | LL | (a.clone(), a.clone()) | ^ -error: redundant clone - --> $DIR/redundant_clone.rs:121:15 - | -LL | let _s = s.clone(); - | ^^^^^^^^ help: remove this - | -note: this value is dropped without further use - --> $DIR/redundant_clone.rs:121:14 - | -LL | let _s = s.clone(); - | ^ - error: redundant clone --> $DIR/redundant_clone.rs:122:15 | -LL | let _t = t.clone(); +LL | let _s = s.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use --> $DIR/redundant_clone.rs:122:14 | +LL | let _s = s.clone(); + | ^ + +error: redundant clone + --> $DIR/redundant_clone.rs:123:15 + | +LL | let _t = t.clone(); + | ^^^^^^^^ help: remove this + | +note: this value is dropped without further use + --> $DIR/redundant_clone.rs:123:14 + | LL | let _t = t.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:132:19 + --> $DIR/redundant_clone.rs:133:19 | LL | let _f = f.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:132:18 + --> $DIR/redundant_clone.rs:133:18 | LL | let _f = f.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:144:14 + --> $DIR/redundant_clone.rs:145:14 | LL | let y = x.clone().join("matthias"); | ^^^^^^^^ help: remove this | note: cloned value is neither consumed nor mutated - --> $DIR/redundant_clone.rs:144:13 + --> $DIR/redundant_clone.rs:145:13 | LL | let y = x.clone().join("matthias"); | ^^^^^^^^^ From b7c8b96e668a1e3c84cf559de1426c6eebd7d1c1 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 22 Jun 2020 13:22:45 +0100 Subject: [PATCH 33/36] trait_sel: only test predicates w/ no substs This commit modifies the `substitute_normalize_and_test_predicates` query, renaming it to `impossible_predicates` and only checking predicates which do not require substs. By making this change, polymorphization doesn't have to explicitly support vtables. Signed-off-by: David Wood --- clippy_lints/src/utils/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 4b163fba528..a4bee1c2780 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1346,7 +1346,7 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool { .predicates .iter() .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None }); - !traits::normalize_and_test_predicates( + traits::impossible_predicates( cx.tcx, traits::elaborate_predicates(cx.tcx, predicates) .map(|o| o.predicate) From 142a273441d1cf2039bd2857ee57cfa402e2a3f7 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 22 Jul 2020 05:23:55 +0900 Subject: [PATCH 34/36] Use `(std::)f64::EPSILON` in the examples as suggested in the lints --- clippy_lints/src/misc.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index fc10e5077b8..26a1c32b6b3 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -99,7 +99,9 @@ declare_clippy_lint! { /// if y != x {} // where both are floats /// /// // Good - /// let error = 0.01f64; // Use an epsilon for comparison + /// let error = f64::EPSILON; // Use an epsilon for comparison + /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead. + /// // let error = std::f64::EPSILON; /// if (y - 1.23f64).abs() < error { } /// if (y - x).abs() > error { } /// ``` @@ -237,10 +239,12 @@ declare_clippy_lint! { /// const ONE: f64 = 1.00; /// /// // Bad - /// if x == ONE { } // where both are floats + /// if x == ONE { } // where both are floats /// /// // Good - /// let error = 0.1f64; // Use an epsilon for comparison + /// let error = f64::EPSILON; // Use an epsilon for comparison + /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead. + /// // let error = std::f64::EPSILON; /// if (x - ONE).abs() < error { } /// ``` pub FLOAT_CMP_CONST, From bdc01c882e5f212c9a8a0384aef1b670122a4337 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Wed, 22 Jul 2020 18:07:33 +0200 Subject: [PATCH 35/36] Update Usage section of README.md --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 222b81023a7..a2984d73641 100644 --- a/README.md +++ b/README.md @@ -42,10 +42,8 @@ Table of contents: ## Usage -Since this is a tool for helping the developer of a library or application -write better code, it is recommended not to include Clippy as a hard dependency. -Options include using it as an optional dependency, as a cargo subcommand, or -as an included feature during build. These options are detailed below. +Below are instructions on how to use Clippy as a subcommand, compiled from source +or in Travis CI. ### As a cargo subcommand (`cargo clippy`) From c81bbd05b95ae03da9af4e7e25e3784edd039465 Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Sat, 25 Jul 2020 23:58:22 +0900 Subject: [PATCH 36/36] Fix FP `useless_conversion` Fix #5833. --- clippy_lints/src/useless_conversion.rs | 11 +++++++++-- tests/ui/useless_conversion.fixed | 9 +++++++++ tests/ui/useless_conversion.rs | 9 +++++++++ tests/ui/useless_conversion.stderr | 14 +++++++------- 4 files changed, 34 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index a48ad3185e9..1bf37632e32 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -1,6 +1,6 @@ use crate::utils::{ - 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, 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; @@ -79,6 +79,13 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } } if match_trait_method(cx, e, &paths::INTO_ITERATOR) && &*name.ident.as_str() == "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" { + return; + } + } + } let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(&args[0]); if TyS::same_type(a, b) { diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index fdd4bc581f3..813cdaecaa9 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -32,11 +32,20 @@ fn test_issue_3913() -> Result<(), std::io::Error> { Ok(()) } +fn test_issue_5833() -> Result<(), ()> { + let text = "foo\r\nbar\n\nbaz\n"; + let lines = text.lines(); + if Some("ok") == lines.into_iter().next() {} + + Ok(()) +} + fn main() { test_generic(10i32); test_generic2::(10i32); test_questionmark().unwrap(); test_issue_3913().unwrap(); + test_issue_5833().unwrap(); let _: String = "foo".into(); let _: String = From::from("foo"); diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index 4cae745e7c0..540fea23b36 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -32,11 +32,20 @@ fn test_issue_3913() -> Result<(), std::io::Error> { Ok(()) } +fn test_issue_5833() -> Result<(), ()> { + let text = "foo\r\nbar\n\nbaz\n"; + let lines = text.lines(); + if Some("ok") == lines.into_iter().next() {} + + Ok(()) +} + fn main() { test_generic(10i32); test_generic2::(10i32); test_questionmark().unwrap(); test_issue_3913().unwrap(); + test_issue_5833().unwrap(); let _: String = "foo".into(); let _: String = From::from("foo"); diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index 84ec5370278..b958b035452 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -23,43 +23,43 @@ LL | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` error: useless conversion to the same type - --> $DIR/useless_conversion.rs:51:21 + --> $DIR/useless_conversion.rs:60:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` error: useless conversion to the same type - --> $DIR/useless_conversion.rs:52:21 + --> $DIR/useless_conversion.rs:61:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` error: useless conversion to the same type - --> $DIR/useless_conversion.rs:53:13 + --> $DIR/useless_conversion.rs:62:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` error: useless conversion to the same type - --> $DIR/useless_conversion.rs:54:13 + --> $DIR/useless_conversion.rs:63:13 | LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` error: useless conversion to the same type - --> $DIR/useless_conversion.rs:55:13 + --> $DIR/useless_conversion.rs:64:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` error: useless conversion to the same type - --> $DIR/useless_conversion.rs:56:13 + --> $DIR/useless_conversion.rs:65:13 | LL | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` error: useless conversion to the same type - --> $DIR/useless_conversion.rs:57:21 + --> $DIR/useless_conversion.rs:66:21 | LL | let _: String = format!("Hello {}", "world").into(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")`