From b632c922138bf77d698b900207d26bcf44bd90b4 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 7 Apr 2021 16:19:25 -0400 Subject: [PATCH] Remove all usages of `match_path` and `match_qpath` except the `author` lint. --- clippy_lints/src/if_then_some_else_none.rs | 8 +- clippy_lints/src/implicit_hasher.rs | 7 +- clippy_lints/src/implicit_saturating_sub.rs | 34 +++++-- clippy_lints/src/infinite_iter.rs | 4 +- clippy_lints/src/manual_ok_or.rs | 16 ++- clippy_lints/src/manual_unwrap_or.rs | 14 +-- clippy_lints/src/map_identity.rs | 7 +- clippy_lints/src/matches.rs | 97 +++++++++++-------- clippy_lints/src/mem_replace.rs | 4 +- .../src/methods/filter_map_identity.rs | 12 +-- clippy_lints/src/methods/flat_map_identity.rs | 18 +--- .../methods/from_iter_instead_of_collect.rs | 11 +-- .../methods/manual_saturating_arithmetic.rs | 6 +- clippy_lints/src/methods/mod.rs | 2 +- .../src/methods/option_map_or_none.rs | 18 +--- .../src/methods/uninit_assumed_init.rs | 5 +- .../src/methods/unnecessary_filter_map.rs | 22 ++--- clippy_lints/src/misc.rs | 12 +-- clippy_lints/src/option_if_let_else.rs | 4 +- clippy_lints/src/ptr.rs | 17 ++-- clippy_lints/src/question_mark.rs | 9 +- clippy_lints/src/returns.rs | 7 +- .../src/slow_vector_initialization.rs | 67 ++++++------- clippy_lints/src/transmuting_null.rs | 21 ++-- clippy_lints/src/try_err.rs | 5 +- clippy_lints/src/types/borrowed_box.rs | 9 +- clippy_lints/src/unnecessary_wraps.rs | 15 ++- clippy_lints/src/utils/internal_lints.rs | 13 ++- clippy_utils/src/lib.rs | 69 +++++++++++-- clippy_utils/src/paths.rs | 31 +++++- doc/adding_lints.md | 2 +- .../collapsible_span_lint_calls.fixed | 48 +-------- .../collapsible_span_lint_calls.rs | 48 +-------- .../collapsible_span_lint_calls.stderr | 10 +- tests/ui-internal/match_type_on_diag_item.rs | 19 +--- .../match_type_on_diag_item.stderr | 30 +++--- tests/ui/repl_uninit.stderr | 10 +- 37 files changed, 344 insertions(+), 387 deletions(-) diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index ee16519692f9..67a2d3a3fb2d 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet_with_macro_callsite; -use clippy_utils::{match_qpath, meets_msrv, parent_node_is_if_expr}; +use clippy_utils::{match_def_path, meets_msrv, parent_node_is_if_expr}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -77,12 +77,14 @@ impl LateLintPass<'_> for IfThenSomeElseNone { if let Some(then_expr) = then_block.expr; if let ExprKind::Call(then_call, [then_arg]) = then_expr.kind; if let ExprKind::Path(ref then_call_qpath) = then_call.kind; - if match_qpath(then_call_qpath, &clippy_utils::paths::OPTION_SOME); + if let Some(then_call_did) = cx.qpath_res(then_call_qpath, then_expr.hir_id).opt_def_id(); + if match_def_path(cx, then_call_did, &clippy_utils::paths::OPTION_SOME); if let ExprKind::Block(els_block, _) = els.kind; if els_block.stmts.is_empty(); if let Some(els_expr) = els_block.expr; if let ExprKind::Path(ref els_call_qpath) = els_expr.kind; - if match_qpath(els_call_qpath, &clippy_utils::paths::OPTION_NONE); + if let Some(els_call_did) = cx.qpath_res(els_call_qpath, els_expr.hir_id).opt_def_id(); + if match_def_path(cx, els_call_did, &clippy_utils::paths::OPTION_NONE); then { let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]"); let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) { diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index 77a38544edc8..03fe0d16d480 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -22,7 +22,7 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::paths; use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{differing_macro_contexts, match_path}; +use clippy_utils::{differing_macro_contexts, match_def_path}; declare_clippy_lint! { /// **What it does:** Checks for public `impl` or `fn` missing generalization @@ -333,12 +333,13 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't if let ExprKind::Call(fun, args) = e.kind; if let ExprKind::Path(QPath::TypeRelative(ty, method)) = fun.kind; if let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind; + if let Some(ty_did) = ty_path.res.opt_def_id(); then { if !TyS::same_type(self.target.ty(), self.maybe_typeck_results.unwrap().expr_ty(e)) { return; } - if match_path(ty_path, &paths::HASHMAP) { + if match_def_path(self.cx, ty_did, &paths::HASHMAP) { if method.ident.name == sym::new { self.suggestions .insert(e.span, "HashMap::default()".to_string()); @@ -351,7 +352,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't ), ); } - } else if match_path(ty_path, &paths::HASHSET) { + } else if match_def_path(self.cx, ty_did, &paths::HASHSET) { if method.ident.name == sym::new { self.suggestions .insert(e.span, "HashSet::default()".to_string()); diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index cba3183e8695..87f4c7aba24f 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{in_macro, match_qpath, SpanlessEq}; +use clippy_utils::{in_macro, match_any_expr_path_res, match_any_qpath_res, paths, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -87,7 +87,6 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { // Get the variable name let var_name = ares_path.segments[0].ident.name.as_str(); - const INT_TYPES: [&str; 5] = ["i8", "i16", "i32", "i64", "i128"]; match cond_num_val.kind { ExprKind::Lit(ref cond_lit) => { @@ -100,16 +99,31 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { } }, ExprKind::Path(ref cond_num_path) => { - if INT_TYPES.iter().any(|int_type| match_qpath(cond_num_path, &[int_type, "MIN"])) { + if match_any_qpath_res(cx, cond_num_path, cond_num_val.hir_id, &[ + &paths::I8_MIN, + &paths::I16_MIN, + &paths::I32_MIN, + &paths::I64_MIN, + &paths::ISIZE_MIN, + &paths::I8_MOD_MIN, + &paths::I16_MOD_MIN, + &paths::I32_MOD_MIN, + &paths::I64_MOD_MIN, + &paths::ISIZE_MOD_MIN, + ]).is_some() { print_lint_and_sugg(cx, &var_name, expr); - }; + } }, - ExprKind::Call(func, _) => { - if let ExprKind::Path(ref cond_num_path) = func.kind { - if INT_TYPES.iter().any(|int_type| match_qpath(cond_num_path, &[int_type, "min_value"])) { - print_lint_and_sugg(cx, &var_name, expr); - } - }; + ExprKind::Call(func, []) => { + if match_any_expr_path_res(cx, func, &[ + &paths::I8_MIN_VALUE, + &paths::I16_MIN_VALUE, + &paths::I32_MIN_VALUE, + &paths::I64_MIN_VALUE, + &paths::ISIZE_MIN_VALUE, + ]).is_some() { + print_lint_and_sugg(cx, &var_name, expr); + } }, _ => (), } diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index bbb4ddc613af..9a0ce7116ba8 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{implements_trait, match_type}; -use clippy_utils::{get_trait_def_id, higher, match_qpath, paths}; +use clippy_utils::{get_trait_def_id, higher, match_qpath_res, paths}; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -163,7 +163,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e), ExprKind::Call(path, _) => { if let ExprKind::Path(ref qpath) = path.kind { - match_qpath(qpath, &paths::REPEAT).into() + match_qpath_res(cx, qpath, path.hir_id, &paths::ITER_REPEAT).into() } else { Finite } diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs index 9bfae602c407..565a3bf00d11 100644 --- a/clippy_lints/src/manual_ok_or.rs +++ b/clippy_lints/src/manual_ok_or.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{match_qpath, path_to_local_id, paths}; +use clippy_utils::{match_expr_path_res, path_to_local_id, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, PatKind}; @@ -53,8 +53,8 @@ impl LateLintPass<'_> for ManualOkOr { if is_type_diagnostic_item(cx, ty, sym::option_type); let or_expr = &args[1]; if is_ok_wrapping(cx, &args[2]); - if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, &[ref err_arg]) = or_expr.kind; - if match_qpath(err_path, &paths::RESULT_ERR); + if let ExprKind::Call(err_expr, &[ref err_arg]) = or_expr.kind; + if match_expr_path_res(cx, err_expr, &paths::RESULT_ERR); if let Some(method_receiver_snippet) = snippet_opt(cx, method_receiver.span); if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span); if let Some(indent) = indent_of(cx, scrutinee.span); @@ -80,17 +80,15 @@ impl LateLintPass<'_> for ManualOkOr { } fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool { - if let ExprKind::Path(ref qpath) = map_expr.kind { - if match_qpath(qpath, &paths::RESULT_OK) { - return true; - } + if match_expr_path_res(cx, map_expr, &paths::RESULT_OK) { + return true; } if_chain! { if let ExprKind::Closure(_, _, body_id, ..) = map_expr.kind; let body = cx.tcx.hir().body(body_id); if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind; - if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind; - if match_qpath(ok_path, &paths::RESULT_OK); + if let ExprKind::Call(ok_expr, &[ref ok_arg]) = body.value.kind; + if match_expr_path_res(cx, ok_expr, &paths::RESULT_OK); then { path_to_local_id(ok_arg, param_id) } else { false } } } diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs index f296d6a1a15f..0cab754d8323 100644 --- a/clippy_lints/src/manual_unwrap_or.rs +++ b/clippy_lints/src/manual_unwrap_or.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::contains_return_break_continue_macro; -use clippy_utils::{in_constant, match_qpath, path_to_local_id, paths, sugg}; +use clippy_utils::{in_constant, match_qpath_res, path_to_local_id, paths, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Arm, Expr, ExprKind, Pat, PatKind}; @@ -68,23 +68,23 @@ impl Case { } fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - fn applicable_or_arm<'a>(arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> { + fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> { if_chain! { if arms.len() == 2; if arms.iter().all(|arm| arm.guard.is_none()); if let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| match arm.pat.kind { PatKind::Path(ref some_qpath) => - match_qpath(some_qpath, &paths::OPTION_NONE), + match_qpath_res(cx, some_qpath, arm.pat.hir_id, &paths::OPTION_NONE), PatKind::TupleStruct(ref err_qpath, &[Pat { kind: PatKind::Wild, .. }], _) => - match_qpath(err_qpath, &paths::RESULT_ERR), + match_qpath_res(cx, err_qpath, arm.pat.hir_id, &paths::RESULT_ERR), _ => false, } ); let unwrap_arm = &arms[1 - idx]; if let PatKind::TupleStruct(ref unwrap_qpath, &[unwrap_pat], _) = unwrap_arm.pat.kind; - if match_qpath(unwrap_qpath, &paths::OPTION_SOME) - || match_qpath(unwrap_qpath, &paths::RESULT_OK); + if match_qpath_res(cx, unwrap_qpath, unwrap_arm.hir_id, &paths::OPTION_SOME) + || match_qpath_res(cx, unwrap_qpath, unwrap_arm.hir_id, &paths::RESULT_OK); if let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind; if path_to_local_id(unwrap_arm.body, binding_hir_id); if !contains_return_break_continue_macro(or_arm.body); @@ -106,7 +106,7 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { } else { None }; - if let Some(or_arm) = applicable_or_arm(match_arms); + if let Some(or_arm) = applicable_or_arm(cx, match_arms); if let Some(or_body_snippet) = snippet_opt(cx, or_arm.body.span); if let Some(indent) = indent_of(cx, expr.span); if constant_simple(cx, cx.typeck_results(), or_arm.body).is_some(); diff --git a/clippy_lints/src/map_identity.rs b/clippy_lints/src/map_identity.rs index e7719e7663d6..f19bb47224cf 100644 --- a/clippy_lints/src/map_identity.rs +++ b/clippy_lints/src/map_identity.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_adjusted, is_trait_method, match_path, match_var, paths, remove_blocks}; +use clippy_utils::{is_adjusted, is_trait_method, match_def_path, match_var, paths, remove_blocks}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Body, Expr, ExprKind, Pat, PatKind, QPath, StmtKind}; @@ -80,7 +80,10 @@ fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match expr.kind { ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)), - ExprKind::Path(QPath::Resolved(_, path)) => match_path(path, &paths::STD_CONVERT_IDENTITY), + ExprKind::Path(QPath::Resolved(_, path)) => path + .res + .opt_def_id() + .map_or(false, |id| match_def_path(cx, id, &paths::CONVERT_IDENTITY)), _ => false, } } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index a892e24482b9..26e7dda67a64 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -7,8 +7,9 @@ use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs}; use clippy_utils::visitors::LocalUsedVisitor; use clippy_utils::{ - get_parent_expr, in_macro, is_allowed, is_expn_of, is_refutable, is_wild, match_qpath, meets_msrv, path_to_local, - path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, remove_blocks, strip_pat_refs, + get_parent_expr, in_macro, is_allowed, is_expn_of, is_refutable, is_wild, match_expr_path_res, match_qpath_res, + meets_msrv, path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, + remove_blocks, strip_pat_refs, }; use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash}; use if_chain::if_chain; @@ -1188,10 +1189,10 @@ fn check_match_ref_pats(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], e fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) { if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() { - let arm_ref: Option = if is_none_arm(&arms[0]) { - is_ref_some_arm(&arms[1]) - } else if is_none_arm(&arms[1]) { - is_ref_some_arm(&arms[0]) + let arm_ref: Option = if is_none_arm(cx, &arms[0]) { + is_ref_some_arm(cx, &arms[1]) + } else if is_none_arm(cx, &arms[1]) { + is_ref_some_arm(cx, &arms[0]) } else { None }; @@ -1574,22 +1575,20 @@ fn is_unit_expr(expr: &Expr<'_>) -> bool { } // Checks if arm has the form `None => None` -fn is_none_arm(arm: &Arm<'_>) -> bool { - matches!(arm.pat.kind, PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE)) +fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { + matches!(arm.pat.kind, PatKind::Path(ref path) if match_qpath_res(cx, path, arm.pat.hir_id, &paths::OPTION_NONE)) } // Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`) -fn is_ref_some_arm(arm: &Arm<'_>) -> Option { +fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option { if_chain! { - if let PatKind::TupleStruct(ref path, pats, _) = arm.pat.kind; - if pats.len() == 1 && match_qpath(path, &paths::OPTION_SOME); - if let PatKind::Binding(rb, .., ident, _) = pats[0].kind; + if let PatKind::TupleStruct(ref path, [pat], _) = arm.pat.kind; + if match_qpath_res(cx, path, arm.pat.hir_id, &paths::OPTION_SOME); + if let PatKind::Binding(rb, local_id, _, _) = pat.kind; if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut; - if let ExprKind::Call(e, args) = remove_blocks(arm.body).kind; - if let ExprKind::Path(ref some_path) = e.kind; - if match_qpath(some_path, &paths::OPTION_SOME) && args.len() == 1; - if let ExprKind::Path(QPath::Resolved(_, path2)) = args[0].kind; - if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name; + if let ExprKind::Call(e, [arg]) = remove_blocks(arm.body).kind; + if match_expr_path_res(cx, e, &paths::OPTION_SOME); + if path_to_local_id(arg, local_id); then { return Some(rb) } @@ -1699,7 +1698,7 @@ mod redundant_pattern_match { use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; - use clippy_utils::{is_trait_method, match_qpath, paths}; + use clippy_utils::{is_trait_method, match_any_qpath_res, match_qpath_res, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -1734,32 +1733,41 @@ mod redundant_pattern_match { let good_method = match kind { PatKind::TupleStruct(ref path, patterns, _) if patterns.len() == 1 => { if let PatKind::Wild = patterns[0].kind { - if match_qpath(path, &paths::RESULT_OK) { - "is_ok()" - } else if match_qpath(path, &paths::RESULT_ERR) { - "is_err()" - } else if match_qpath(path, &paths::OPTION_SOME) { - "is_some()" - } else if match_qpath(path, &paths::POLL_READY) { - "is_ready()" - } else if match_qpath(path, &paths::IPADDR_V4) { - "is_ipv4()" - } else if match_qpath(path, &paths::IPADDR_V6) { - "is_ipv6()" - } else { - return; + match match_any_qpath_res( + cx, + path, + arms[0].pat.hir_id, + &[ + &paths::RESULT_OK, + &paths::RESULT_ERR, + &paths::OPTION_SOME, + &paths::POLL_READY, + &paths::IPADDR_V4, + &paths::IPADDR_V6, + ], + ) { + Some(0) => "is_ok()", + Some(1) => "is_err()", + Some(2) => "is_some()", + Some(3) => "is_ready()", + Some(4) => "is_ipv4()", + Some(5) => "is_ipv6()", + _ => return, } } else { return; } }, PatKind::Path(ref path) => { - if match_qpath(path, &paths::OPTION_NONE) { - "is_none()" - } else if match_qpath(path, &paths::POLL_PENDING) { - "is_pending()" - } else { - return; + match match_any_qpath_res( + cx, + path, + arms[0].pat.hir_id, + &[&paths::OPTION_NONE, &paths::POLL_PENDING], + ) { + Some(0) => "is_none()", + Some(1) => "is_pending()", + _ => return, } }, _ => return, @@ -1818,6 +1826,7 @@ mod redundant_pattern_match { ) if patterns_left.len() == 1 && patterns_right.len() == 1 => { if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) { find_good_method_for_match( + cx, arms, path_left, path_right, @@ -1828,6 +1837,7 @@ mod redundant_pattern_match { ) .or_else(|| { find_good_method_for_match( + cx, arms, path_left, path_right, @@ -1847,6 +1857,7 @@ mod redundant_pattern_match { { if let PatKind::Wild = patterns[0].kind { find_good_method_for_match( + cx, arms, path_left, path_right, @@ -1857,6 +1868,7 @@ mod redundant_pattern_match { ) .or_else(|| { find_good_method_for_match( + cx, arms, path_left, path_right, @@ -1898,6 +1910,7 @@ mod redundant_pattern_match { } fn find_good_method_for_match<'a>( + cx: &LateContext<'_>, arms: &[Arm<'_>], path_left: &QPath<'_>, path_right: &QPath<'_>, @@ -1906,9 +1919,13 @@ mod redundant_pattern_match { should_be_left: &'a str, should_be_right: &'a str, ) -> Option<&'a str> { - let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) { + let body_node_pair = if match_qpath_res(cx, path_left, arms[0].pat.hir_id, expected_left) + && match_qpath_res(cx, path_right, arms[1].pat.hir_id, expected_right) + { (&(*arms[0].body).kind, &(*arms[1].body).kind) - } else if match_qpath(path_right, expected_left) && match_qpath(path_left, expected_right) { + } else if match_qpath_res(cx, path_right, arms[1].pat.hir_id, expected_left) + && match_qpath_res(cx, path_left, arms[0].pat.hir_id, expected_right) + { (&(*arms[1].body).kind, &(*arms[0].body).kind) } else { return None; diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index e1d351aee454..4df27823e6a2 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diagnostic_assoc_item; use clippy_utils::source::{snippet, snippet_with_applicability}; -use clippy_utils::{in_macro, match_def_path, match_qpath, meets_msrv, paths}; +use clippy_utils::{in_macro, match_def_path, match_qpath_res, meets_msrv, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; @@ -102,7 +102,7 @@ impl_lint_pass!(MemReplace => fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { if let ExprKind::Path(ref replacement_qpath) = src.kind { // Check that second argument is `Option::None` - if match_qpath(replacement_qpath, &paths::OPTION_NONE) { + if match_qpath_res(cx, replacement_qpath, src.hir_id, &paths::OPTION_NONE) { // Since this is a late pass (already type-checked), // and we already know that the second argument is an // `Option`, we do not need to check the first diff --git a/clippy_lints/src/methods/filter_map_identity.rs b/clippy_lints/src/methods/filter_map_identity.rs index 3a61f4ccad78..e0b62d957eeb 100644 --- a/clippy_lints/src/methods/filter_map_identity.rs +++ b/clippy_lints/src/methods/filter_map_identity.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_trait_method, match_qpath, path_to_local_id, paths}; +use clippy_utils::{is_trait_method, match_expr_path_res, path_to_local_id, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -33,14 +33,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: } } - if_chain! { - if let hir::ExprKind::Path(ref qpath) = filter_map_arg.kind; - - if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY); - - then { - apply_lint("called `filter_map(std::convert::identity)` on an `Iterator`"); - } + if match_expr_path_res(cx, filter_map_arg, &paths::CONVERT_IDENTITY) { + apply_lint("called `filter_map(std::convert::identity)` on an `Iterator`"); } } } diff --git a/clippy_lints/src/methods/flat_map_identity.rs b/clippy_lints/src/methods/flat_map_identity.rs index dd613d0cd638..df0ac06078ea 100644 --- a/clippy_lints/src/methods/flat_map_identity.rs +++ b/clippy_lints/src/methods/flat_map_identity.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::{is_trait_method, match_qpath, paths}; +use clippy_utils::{is_trait_method, match_expr_path_res, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -16,8 +16,6 @@ pub(super) fn check<'tcx>( flat_map_span: Span, ) { if is_trait_method(cx, expr, sym::Iterator) { - let arg_node = &flat_map_arg.kind; - let apply_lint = |message: &str| { span_lint_and_sugg( cx, @@ -31,8 +29,8 @@ pub(super) fn check<'tcx>( }; if_chain! { - if let hir::ExprKind::Closure(_, _, body_id, _, _) = arg_node; - let body = cx.tcx.hir().body(*body_id); + if let hir::ExprKind::Closure(_, _, body_id, _, _) = flat_map_arg.kind; + let body = cx.tcx.hir().body(body_id); if let hir::PatKind::Binding(_, _, binding_ident, _) = body.params[0].pat.kind; if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = body.value.kind; @@ -45,14 +43,8 @@ pub(super) fn check<'tcx>( } } - if_chain! { - if let hir::ExprKind::Path(ref qpath) = arg_node; - - if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY); - - then { - apply_lint("called `flat_map(std::convert::identity)` on an `Iterator`"); - } + if match_expr_path_res(cx, flat_map_arg, &paths::CONVERT_IDENTITY) { + apply_lint("called `flat_map(std::convert::identity)` on an `Iterator`"); } } } diff --git a/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 707c54f7a3ca..702353e73a7f 100644 --- a/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -1,26 +1,23 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::implements_trait; -use clippy_utils::{get_trait_def_id, match_qpath, paths, sugg}; +use clippy_utils::{match_expr_path_res, paths, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::ExprKind; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::Ty; use rustc_span::sym; use super::FROM_ITER_INSTEAD_OF_COLLECT; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>], func_kind: &ExprKind<'_>) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>], func: &hir::Expr<'_>) { if_chain! { - if let hir::ExprKind::Path(path) = func_kind; - if match_qpath(path, &["from_iter"]); + if match_expr_path_res(cx, func, &paths::FROM_ITERATOR_METHOD); let ty = cx.typeck_results().expr_ty(expr); let arg_ty = cx.typeck_results().expr_ty(&args[0]); - if let Some(from_iter_id) = get_trait_def_id(cx, &paths::FROM_ITERATOR); if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator); - if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]); + if implements_trait(cx, arg_ty, iter_id, &[]); then { // `expr` implements `FromIterator` trait let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par(); diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index ecb8b72ef461..8d7552636294 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::match_qpath; +use clippy_utils::match_qpath_res; use clippy_utils::source::snippet_with_applicability; use if_chain::if_chain; use rustc_ast::ast; @@ -94,11 +94,11 @@ fn is_min_or_max<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) -> Option LateLintPass<'tcx> for Methods { match expr.kind { hir::ExprKind::Call(func, args) => { - from_iter_instead_of_collect::check(cx, expr, args, &func.kind); + from_iter_instead_of_collect::check(cx, expr, args, func); }, hir::ExprKind::MethodCall(method_call, ref method_span, args, _) => { or_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args); diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index 013a6f90ac97..be1a9768cfd6 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{match_qpath, paths}; +use clippy_utils::{match_expr_path_res, paths}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -31,23 +31,11 @@ pub(super) fn check<'tcx>( } let (lint_name, msg, instead, hint) = { - let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = def_arg.kind { - match_qpath(qpath, &paths::OPTION_NONE) - } else { - return; - }; - - if !default_arg_is_none { + if !match_expr_path_res(cx, def_arg, &paths::OPTION_NONE) { // nothing to lint! return; } - let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_arg.kind { - match_qpath(qpath, &paths::OPTION_SOME) - } else { - false - }; - if is_option { let self_snippet = snippet(cx, recv.span, ".."); let func_snippet = snippet(cx, map_arg.span, ".."); @@ -59,7 +47,7 @@ pub(super) fn check<'tcx>( "try using `and_then` instead", format!("{0}.and_then({1})", self_snippet, func_snippet), ) - } else if f_arg_is_some { + } else if match_expr_path_res(cx, map_arg, &paths::OPTION_SOME) { let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \ `ok()` instead"; let self_snippet = snippet(cx, recv.span, ".."); diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs index 0ae65c0c01db..e9320bb79043 100644 --- a/clippy_lints/src/methods/uninit_assumed_init.rs +++ b/clippy_lints/src/methods/uninit_assumed_init.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{match_def_path, match_qpath, paths}; +use clippy_utils::{match_def_path, match_expr_path_res, paths}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; @@ -12,8 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr if_chain! { if let hir::ExprKind::Call(callee, args) = recv.kind; if args.is_empty(); - if let hir::ExprKind::Path(ref path) = callee.kind; - if match_qpath(path, &paths::MEM_MAYBEUNINIT_UNINIT); + if match_expr_path_res(cx, callee, &paths::MEM_MAYBEUNINIT_UNINIT); if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(expr)); then { span_lint( diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index 0f28bfdf09e8..7cec3d76aae5 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::usage::mutated_variables; -use clippy_utils::{is_trait_method, match_qpath, path_to_local_id, paths}; +use clippy_utils::{is_trait_method, match_expr_path_res, match_qpath_res, path_to_local_id, paths}; use rustc_hir as hir; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_lint::LateContext; @@ -52,18 +52,16 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr< // returns (found_mapping, found_filtering) fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tcx hir::Expr<'_>) -> (bool, bool) { match &expr.kind { - hir::ExprKind::Call(func, args) => { - if let hir::ExprKind::Path(ref path) = func.kind { - if match_qpath(path, &paths::OPTION_SOME) { - if path_to_local_id(&args[0], arg_id) { - return (false, false); - } - return (true, false); + hir::ExprKind::Call(func, [arg]) => { + if match_expr_path_res(cx, func, &paths::OPTION_SOME) { + if path_to_local_id(arg, arg_id) { + (false, false) + } else { + (true, false) } - // We don't know. It might do anything. - return (true, true); + } else { + (true, true) } - (true, true) }, hir::ExprKind::Block(block, _) => block .expr @@ -85,7 +83,7 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc let else_check = check_expression(cx, arg_id, else_arm); (if_check.0 | else_check.0, if_check.1 | else_check.1) }, - hir::ExprKind::Path(path) if match_qpath(path, &paths::OPTION_NONE) => (false, true), + hir::ExprKind::Path(path) if match_qpath_res(cx, path, expr.hir_id, &paths::OPTION_NONE) => (false, true), _ => (true, true), } } diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index afced5a5ce58..f60b55fa1aaa 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -21,7 +21,7 @@ use crate::consts::{constant, Constant}; use clippy_utils::sugg::Sugg; use clippy_utils::{ get_item_name, get_parent_expr, higher, in_constant, is_diagnostic_assoc_item, is_integer_const, iter_input_pats, - last_path_segment, match_qpath, unsext, SpanlessEq, + last_path_segment, match_any_expr_path_res, paths, unsext, SpanlessEq, }; declare_clippy_lint! { @@ -564,13 +564,9 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: } ) }, - ExprKind::Call(path, v) if v.len() == 1 => { - if let ExprKind::Path(ref path) = path.kind { - if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) { - (cx.typeck_results().expr_ty(&v[0]), snippet(cx, v[0].span, "..")) - } else { - return; - } + ExprKind::Call(path, [arg]) => { + if match_any_expr_path_res(cx, path, &[&paths::FROM_STR_METHOD, &paths::FROM_FROM]).is_some() { + (cx.typeck_results().expr_ty(arg), snippet(cx, arg.span, "..")) } else { return; } diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 1b9120ae45f5..617233b2e552 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -3,7 +3,7 @@ use clippy_utils::paths; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::contains_return_break_continue_macro; -use clippy_utils::{eager_or_lazy, get_enclosing_block, in_macro, match_qpath}; +use clippy_utils::{eager_or_lazy, get_enclosing_block, in_macro, match_qpath_res}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, MatchSource, Mutability, PatKind, UnOp}; @@ -164,7 +164,7 @@ fn detect_option_if_let_else<'tcx>( if arms.len() == 2; if !is_result_ok(cx, cond_expr); // Don't lint on Result::ok because a different lint does it already if let PatKind::TupleStruct(struct_qpath, &[inner_pat], _) = &arms[0].pat.kind; - if match_qpath(struct_qpath, &paths::OPTION_SOME); + if match_qpath_res(cx, struct_qpath, arms[0].hir_id, &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); diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 09fcdb5faf84..3e202821d83a 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the use clippy_utils::ptr::get_spans; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{is_type_diagnostic_item, match_type, walk_ptrs_hir_ty}; -use clippy_utils::{is_allowed, match_qpath, paths}; +use clippy_utils::{is_allowed, match_any_expr_path_res, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{ @@ -153,7 +153,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Binary(ref op, l, r) = expr.kind { - if (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) && (is_null_path(l) || is_null_path(r)) { + if (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) && (is_null_path(cx, l) || is_null_path(cx, r)) { span_lint( cx, CMP_NULL, @@ -345,13 +345,10 @@ fn get_rptr_lm<'tcx>(ty: &'tcx Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, } } -fn is_null_path(expr: &Expr<'_>) -> bool { - if let ExprKind::Call(pathexp, args) = expr.kind { - if args.is_empty() { - if let ExprKind::Path(ref path) = pathexp.kind { - return match_qpath(path, &paths::PTR_NULL) || match_qpath(path, &paths::PTR_NULL_MUT); - } - } +fn is_null_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let ExprKind::Call(pathexp, []) = expr.kind { + match_any_expr_path_res(cx, pathexp, &[&paths::PTR_NULL, &paths::PTR_NULL_MUT]).is_some() + } else { + false } - false } diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 6d720f43851a..136fc8977d81 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{eq_expr_value, match_def_path, match_qpath, paths}; +use clippy_utils::{eq_expr_value, match_def_path, match_qpath_res, path_to_local_id, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -100,15 +100,14 @@ impl QuestionMark { if Self::is_option(cx, subject); if let PatKind::TupleStruct(path1, fields, None) = &arms[0].pat.kind; - if match_qpath(path1, &["Some"]); - if let PatKind::Binding(annot, _, bind, _) = &fields[0].kind; + if match_qpath_res(cx, path1, arms[0].pat.hir_id, &paths::OPTION_SOME); + if let PatKind::Binding(annot, bind_id, _, _) = fields[0].kind; let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut); if let ExprKind::Block(block, None) = &arms[0].body.kind; if block.stmts.is_empty(); if let Some(trailing_expr) = &block.expr; - if let ExprKind::Path(path) = &trailing_expr.kind; - if match_qpath(path, &[&bind.as_str()]); + if path_to_local_id(trailing_expr, bind_id); if let PatKind::Wild = arms[1].pat.kind; if Self::expression_returns_none(cx, arms[1].body); diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index af772cf4a145..11c6e59c9faa 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_opt; -use clippy_utils::{fn_def_id, in_macro, match_qpath}; +use clippy_utils::{fn_def_id, in_macro, path_to_local_id}; use if_chain::if_chain; use rustc_ast::ast::Attribute; use rustc_errors::Applicability; @@ -84,9 +84,8 @@ impl<'tcx> LateLintPass<'tcx> for Return { if local.ty.is_none(); if cx.tcx.hir().attrs(local.hir_id).is_empty(); if let Some(initexpr) = &local.init; - if let PatKind::Binding(.., ident, _) = local.pat.kind; - if let ExprKind::Path(qpath) = &retexpr.kind; - if match_qpath(qpath, &[&*ident.name.as_str()]); + if let PatKind::Binding(_, local_id, _, _) = local.pat.kind; + if path_to_local_id(retexpr, local_id); if !last_statement_borrows(cx, initexpr); if !in_external_macro(cx.sess(), initexpr.span); if !in_external_macro(cx.sess(), retexpr.span); diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 8cf89ae456ee..e89cb1e8dc5a 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -1,15 +1,14 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::Sugg; -use clippy_utils::{get_enclosing_block, match_qpath, SpanlessEq}; +use clippy_utils::{get_enclosing_block, match_expr_path_res, path_to_local, path_to_local_id, paths, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, NestedVisitorMap, Visitor}; -use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, QPath, Stmt, StmtKind}; +use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::symbol::Symbol; declare_clippy_lint! { /// **What it does:** Checks slow zero-filled vector initialization @@ -46,8 +45,8 @@ declare_lint_pass!(SlowVectorInit => [SLOW_VECTOR_INITIALIZATION]); /// assigned to a variable. For example, `let mut vec = Vec::with_capacity(0)` or /// `vec = Vec::with_capacity(0)` struct VecAllocation<'tcx> { - /// Symbol of the local variable name - variable_name: Symbol, + /// HirId of the variable + local_id: HirId, /// Reference to the expression which allocates the vector allocation_expr: &'tcx Expr<'tcx>, @@ -72,16 +71,15 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit { if_chain! { if let ExprKind::Assign(left, right, _) = expr.kind; - // Extract variable name - if let ExprKind::Path(QPath::Resolved(_, path)) = left.kind; - if let Some(variable_name) = path.segments.get(0); + // Extract variable + if let Some(local_id) = path_to_local(left); // Extract len argument - if let Some(len_arg) = Self::is_vec_with_capacity(right); + if let Some(len_arg) = Self::is_vec_with_capacity(cx, right); then { let vi = VecAllocation { - variable_name: variable_name.ident.name, + local_id, allocation_expr: right, len_expr: len_arg, }; @@ -95,13 +93,13 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit { // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)` if_chain! { if let StmtKind::Local(local) = stmt.kind; - if let PatKind::Binding(BindingAnnotation::Mutable, .., variable_name, None) = local.pat.kind; + if let PatKind::Binding(BindingAnnotation::Mutable, local_id, _, None) = local.pat.kind; if let Some(init) = local.init; - if let Some(len_arg) = Self::is_vec_with_capacity(init); + if let Some(len_arg) = Self::is_vec_with_capacity(cx, init); then { let vi = VecAllocation { - variable_name: variable_name.name, + local_id, allocation_expr: init, len_expr: len_arg, }; @@ -115,19 +113,16 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit { impl SlowVectorInit { /// Checks if the given expression is `Vec::with_capacity(..)`. It will return the expression /// of the first argument of `with_capacity` call if it matches or `None` if it does not. - fn is_vec_with_capacity<'tcx>(expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { + fn is_vec_with_capacity<'tcx>(cx: &LateContext<'_>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { if_chain! { - if let ExprKind::Call(func, args) = expr.kind; - if let ExprKind::Path(ref path) = func.kind; - if match_qpath(path, &["Vec", "with_capacity"]); - if args.len() == 1; - + if let ExprKind::Call(func, [arg]) = expr.kind; + if match_expr_path_res(cx, func, &paths::VEC_WITH_CAPACITY); then { - return Some(&args[0]); + Some(arg) + } else { + None } } - - None } /// Search initialization for the given vector @@ -208,11 +203,9 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) { if_chain! { if self.initialization_found; - if let ExprKind::MethodCall(path, _, args, _) = expr.kind; - if let ExprKind::Path(ref qpath_subj) = args[0].kind; - if match_qpath(qpath_subj, &[&*self.vec_alloc.variable_name.as_str()]); + if let ExprKind::MethodCall(path, _, [self_arg, extend_arg], _) = expr.kind; + if path_to_local_id(self_arg, self.vec_alloc.local_id); if path.ident.name == sym!(extend); - if let Some(extend_arg) = args.get(1); if self.is_repeat_take(extend_arg); then { @@ -225,11 +218,9 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) { if_chain! { if self.initialization_found; - if let ExprKind::MethodCall(path, _, args, _) = expr.kind; - if let ExprKind::Path(ref qpath_subj) = args[0].kind; - if match_qpath(qpath_subj, &[&*self.vec_alloc.variable_name.as_str()]); + if let ExprKind::MethodCall(path, _, [self_arg, len_arg, fill_arg], _) = expr.kind; + if path_to_local_id(self_arg, self.vec_alloc.local_id); if path.ident.name == sym!(resize); - if let (Some(len_arg), Some(fill_arg)) = (args.get(1), args.get(2)); // Check that is filled with 0 if let ExprKind::Lit(ref lit) = fill_arg.kind; @@ -252,7 +243,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { // Check that take is applied to `repeat(0)` if let Some(repeat_expr) = take_args.get(0); - if Self::is_repeat_zero(repeat_expr); + if self.is_repeat_zero(repeat_expr); // Check that len expression is equals to `with_capacity` expression if let Some(len_arg) = take_args.get(1); @@ -267,21 +258,19 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { } /// Returns `true` if given expression is `repeat(0)` - fn is_repeat_zero(expr: &Expr<'_>) -> bool { + fn is_repeat_zero(&self, expr: &Expr<'_>) -> bool { if_chain! { - if let ExprKind::Call(fn_expr, repeat_args) = expr.kind; - if let ExprKind::Path(ref qpath_repeat) = fn_expr.kind; - if match_qpath(qpath_repeat, &["repeat"]); - if let Some(repeat_arg) = repeat_args.get(0); + if let ExprKind::Call(fn_expr, [repeat_arg]) = expr.kind; + if match_expr_path_res(self.cx, fn_expr, &paths::ITER_REPEAT); if let ExprKind::Lit(ref lit) = repeat_arg.kind; if let LitKind::Int(0, _) = lit.node; then { - return true + true + } else { + false } } - - false } } diff --git a/clippy_lints/src/transmuting_null.rs b/clippy_lints/src/transmuting_null.rs index 0be05d3e0cf3..e95c030a687a 100644 --- a/clippy_lints/src/transmuting_null.rs +++ b/clippy_lints/src/transmuting_null.rs @@ -1,6 +1,6 @@ use crate::consts::{constant_context, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::{match_qpath, paths}; +use clippy_utils::{match_expr_path_res, paths}; use if_chain::if_chain; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; @@ -37,18 +37,15 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull { } if_chain! { - if let ExprKind::Call(func, args) = expr.kind; - if let ExprKind::Path(ref path) = func.kind; - if match_qpath(path, &paths::STD_MEM_TRANSMUTE); - if args.len() == 1; + if let ExprKind::Call(func, [arg]) = expr.kind; + if match_expr_path_res(cx, func, &paths::TRANSMUTE); then { - // Catching transmute over constants that resolve to `null`. let mut const_eval_context = constant_context(cx, cx.typeck_results()); if_chain! { - if let ExprKind::Path(ref _qpath) = args[0].kind; - let x = const_eval_context.expr(&args[0]); + if let ExprKind::Path(ref _qpath) = arg.kind; + let x = const_eval_context.expr(arg); if let Some(Constant::RawPtr(0)) = x; then { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG) @@ -58,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull { // Catching: // `std::mem::transmute(0 as *const i32)` if_chain! { - if let ExprKind::Cast(inner_expr, _cast_ty) = args[0].kind; + if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind; if let ExprKind::Lit(ref lit) = inner_expr.kind; if let LitKind::Int(0, _) = lit.node; then { @@ -69,10 +66,8 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull { // Catching: // `std::mem::transmute(std::ptr::null::())` if_chain! { - if let ExprKind::Call(func1, args1) = args[0].kind; - if let ExprKind::Path(ref path1) = func1.kind; - if match_qpath(path1, &paths::STD_PTR_NULL); - if args1.is_empty(); + if let ExprKind::Call(func1, []) = arg.kind; + if match_expr_path_res(cx, func1, &paths::PTR_NULL); then { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG) } diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index 23a1953fface..c2bc61f4a0c9 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{snippet, snippet_with_macro_callsite}; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{differing_macro_contexts, in_macro, match_def_path, match_qpath, paths}; +use clippy_utils::{differing_macro_contexts, in_macro, match_def_path, match_expr_path_res, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath}; @@ -67,8 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { if let Some(try_arg) = try_args.get(0); if let ExprKind::Call(err_fun, err_args) = try_arg.kind; if let Some(err_arg) = err_args.get(0); - if let ExprKind::Path(ref err_fun_path) = err_fun.kind; - if match_qpath(err_fun_path, &paths::RESULT_ERR); + if match_expr_path_res(cx, err_fun, &paths::RESULT_ERR); if let Some(return_ty) = find_return_type(cx, &expr.kind); then { let prefix; diff --git a/clippy_lints/src/types/borrowed_box.rs b/clippy_lints/src/types/borrowed_box.rs index 1425d8f3f37e..bdeff035e5ec 100644 --- a/clippy_lints/src/types/borrowed_box.rs +++ b/clippy_lints/src/types/borrowed_box.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; -use clippy_utils::{match_path, paths}; +use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{ @@ -28,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m _ => None, }); then { - if is_any_trait(inner) { + if is_any_trait(cx, inner) { // Ignore `Box` types; see issue #1884 for details. return false; } @@ -84,13 +84,14 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m } // Returns true if given type is `Any` trait. -fn is_any_trait(t: &hir::Ty<'_>) -> bool { +fn is_any_trait(cx: &LateContext<'_>, t: &hir::Ty<'_>) -> bool { if_chain! { if let TyKind::TraitObject(traits, ..) = t.kind; if !traits.is_empty(); + if let Some(trait_did) = traits[0].trait_ref.trait_def_id(); // Only Send/Sync can be used as additional traits, so it is enough to // check only the first trait. - if match_path(traits[0].trait_ref.path, &paths::ANY_TRAIT); + if match_def_path(cx, trait_did, &paths::ANY_TRAIT); then { return true; } diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index 5bb417cb1be4..2e9e8a7d573c 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -1,6 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; -use clippy_utils::{contains_return, in_macro, match_qpath, paths, return_ty, visitors::find_all_ret_expressions}; +use clippy_utils::{ + contains_return, in_macro, match_expr_path_res, paths, return_ty, visitors::find_all_ret_expressions, +}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; @@ -103,14 +105,11 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { if_chain! { if !in_macro(ret_expr.span); // Check if a function call. - if let ExprKind::Call(func, args) = ret_expr.kind; - // Get the Path of the function call. - if let ExprKind::Path(ref qpath) = func.kind; + if let ExprKind::Call(func, [arg]) = ret_expr.kind; // Check if OPTION_SOME or RESULT_OK, depending on return type. - if match_qpath(qpath, path); - if args.len() == 1; + if match_expr_path_res(cx, func, path); // Make sure the function argument does not contain a return expression. - if !contains_return(&args[0]); + if !contains_return(arg); then { suggs.push( ( @@ -118,7 +117,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { if inner_type.is_unit() { "".to_string() } else { - snippet(cx, args[0].span.source_callsite(), "..").to_string() + snippet(cx, arg.span.source_callsite(), "..").to_string() } ) ); diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index cf8039d6059b..d41147a1b55c 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -3,7 +3,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sug use clippy_utils::source::snippet; use clippy_utils::ty::match_type; use clippy_utils::{ - is_else_clause, is_expn_of, match_def_path, match_qpath, method_calls, path_to_res, paths, run_lints, SpanlessEq, + is_else_clause, is_expn_of, match_def_path, match_expr_path_res, method_calls, path_to_res, paths, run_lints, + SpanlessEq, }; use if_chain::if_chain; use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, ModKind, NodeId}; @@ -578,8 +579,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls { if_chain! { if let ExprKind::Call(func, and_then_args) = expr.kind; - if let ExprKind::Path(ref path) = func.kind; - if match_qpath(path, &["span_lint_and_then"]); + if match_expr_path_res(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"]); if and_then_args.len() == 5; if let ExprKind::Closure(_, _, body_id, _, _) = &and_then_args[4].kind; let body = cx.tcx.hir().body(*body_id); @@ -761,8 +761,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem { if_chain! { // Check if this is a call to utils::match_type() if let ExprKind::Call(fn_path, [context, ty, ty_path]) = expr.kind; - if let ExprKind::Path(fn_qpath) = &fn_path.kind; - if match_qpath(fn_qpath, &["utils", "match_type"]); + if match_expr_path_res(cx, fn_path, &["clippy_utils", "ty", "match_type"]); // Extract the path to the matched type if let Some(segments) = path_to_matched_type(cx, ty_path); let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect(); @@ -778,9 +777,9 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem { cx, MATCH_TYPE_ON_DIAGNOSTIC_ITEM, expr.span, - "usage of `utils::match_type()` on a type diagnostic item", + "usage of `clippy_utils::ty::match_type()` on a type diagnostic item", "try", - format!("utils::is_type_diagnostic_item({}, {}, sym::{})", cx_snippet, ty_snippet, item_name), + format!("clippy_utils::ty::is_type_diagnostic_item({}, {}, sym::{})", cx_snippet, ty_snippet, item_name), Applicability::MaybeIncorrect, ); } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 6088cd323c4b..3df2acb50b75 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -379,6 +379,39 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool { } } +/// Resolves the path to a `DefId` and checks if it matches the given path. +pub fn match_qpath_res(cx: &LateContext<'_>, path: &QPath<'_>, hir_id: HirId, segments: &[&str]) -> bool { + cx.qpath_res(path, hir_id) + .opt_def_id() + .map_or(false, |id| match_def_path(cx, id, segments)) +} + +/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path. +pub fn match_expr_path_res(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool { + if let ExprKind::Path(p) = &expr.kind { + match_qpath_res(cx, p, expr.hir_id, segments) + } else { + false + } +} + +/// Resolves the path to a `DefId` and returns the index of the first matching path, if any. +pub fn match_any_qpath_res(cx: &LateContext<'_>, path: &QPath<'_>, hir_id: HirId, paths: &[&[&str]]) -> Option { + cx.qpath_res(path, hir_id) + .opt_def_id() + .and_then(|id| match_any_def_paths(cx, id, paths)) +} + +/// If the expression is a path, resolves it to a `DefId` and returns the index of the first +/// matching path, if any. +pub fn match_any_expr_path_res(cx: &LateContext<'_>, expr: &Expr<'_>, paths: &[&[&str]]) -> Option { + if let ExprKind::Path(p) = &expr.kind { + match_any_qpath_res(cx, p, expr.hir_id, paths) + } else { + None + } +} + /// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the /// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from /// `QPath::Resolved.1.res.opt_def_id()`. @@ -1130,11 +1163,20 @@ pub fn match_function_call<'tcx>( None } +/// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if +/// any. +pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]]) -> Option { + let search_path = cx.get_def_path(did); + paths + .iter() + .position(|p| p.iter().map(|x| Symbol::intern(x)).eq(search_path.iter().cloned())) +} + +/// Checks if the given `DefId` matches the path. pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) -> bool { - // We have to convert `syms` to `&[Symbol]` here because rustc's `match_def_path` - // accepts only that. We should probably move to Symbols in Clippy as well. - let syms = syms.iter().map(|p| Symbol::intern(p)).collect::>(); - cx.match_def_path(did, &syms) + // We should probably move to Symbols in Clippy as well rather than interning every time. + let path = cx.get_def_path(did); + syms.iter().map(|x| Symbol::intern(x)).eq(path.iter().cloned()) } pub fn match_panic_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx [Expr<'tcx>]> { @@ -1147,12 +1189,19 @@ pub fn match_panic_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> O } pub fn match_panic_def_id(cx: &LateContext<'_>, did: DefId) -> bool { - match_def_path(cx, did, &paths::BEGIN_PANIC) - || match_def_path(cx, did, &paths::BEGIN_PANIC_FMT) - || match_def_path(cx, did, &paths::PANIC_ANY) - || match_def_path(cx, did, &paths::PANICKING_PANIC) - || match_def_path(cx, did, &paths::PANICKING_PANIC_FMT) - || match_def_path(cx, did, &paths::PANICKING_PANIC_STR) + match_any_def_paths( + cx, + did, + &[ + &paths::BEGIN_PANIC, + &paths::BEGIN_PANIC_FMT, + &paths::PANIC_ANY, + &paths::PANICKING_PANIC, + &paths::PANICKING_PANIC_FMT, + &paths::PANICKING_PANIC_STR, + ], + ) + .is_some() } /// Returns the list of condition expressions and the list of blocks in a diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 3b4c4070c0ed..8fceee9b8f16 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -4,7 +4,7 @@ //! Whenever possible, please consider diagnostic items over hardcoded paths. //! See for more information. -pub const ANY_TRAIT: [&str; 3] = ["std", "any", "Any"]; +pub const ANY_TRAIT: [&str; 3] = ["core", "any", "Any"]; pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"]; pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"]; pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"]; @@ -44,11 +44,31 @@ pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"]; pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"]; pub const FROM_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "FromIterator"]; +pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"]; +pub const FROM_STR_METHOD: [&str; 5] = ["core", "str", "traits", "FromStr", "from_str"]; pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"]; pub const HASH: [&str; 3] = ["core", "hash", "Hash"]; pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"]; pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"]; pub const HASHSET: [&str; 5] = ["std", "collections", "hash", "set", "HashSet"]; +pub const I8_MOD_MIN: [&str; 3] = ["core", "i8", "MIN"]; +pub const I16_MOD_MIN: [&str; 3] = ["core", "i16", "MIN"]; +pub const I32_MOD_MIN: [&str; 3] = ["core", "i32", "MIN"]; +pub const I64_MOD_MIN: [&str; 3] = ["core", "i64", "MIN"]; +pub const I128_MOD_MIN: [&str; 3] = ["core", "i128", "MIN"]; +pub const ISIZE_MOD_MIN: [&str; 3] = ["core", "isize", "MIN"]; +pub const I8_MIN: [&str; 4] = ["core", "num", "", "MIN"]; +pub const I16_MIN: [&str; 4] = ["core", "num", "", "MIN"]; +pub const I32_MIN: [&str; 4] = ["core", "num", "", "MIN"]; +pub const I64_MIN: [&str; 4] = ["core", "num", "", "MIN"]; +pub const I128_MIN: [&str; 4] = ["core", "num", "", "MIN"]; +pub const ISIZE_MIN: [&str; 4] = ["core", "num", "", "MIN"]; +pub const I8_MIN_VALUE: [&str; 4] = ["core", "num", "", "min_value"]; +pub const I16_MIN_VALUE: [&str; 4] = ["core", "num", "", "min_value"]; +pub const I32_MIN_VALUE: [&str; 4] = ["core", "num", "", "min_value"]; +pub const I64_MIN_VALUE: [&str; 4] = ["core", "num", "", "min_value"]; +pub const I128_MIN_VALUE: [&str; 4] = ["core", "num", "", "min_value"]; +pub const ISIZE_MIN_VALUE: [&str; 4] = ["core", "num", "", "min_value"]; #[cfg(feature = "internal-lints")] pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"]; #[cfg(feature = "internal-lints")] @@ -60,8 +80,9 @@ pub const INTO: [&str; 3] = ["core", "convert", "Into"]; pub const INTO_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "IntoIterator"]; pub const IO_READ: [&str; 3] = ["std", "io", "Read"]; pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"]; -pub const IPADDR_V4: [&str; 4] = ["std", "net", "IpAddr", "V4"]; -pub const IPADDR_V6: [&str; 4] = ["std", "net", "IpAddr", "V6"]; +pub const IPADDR_V4: [&str; 5] = ["std", "net", "ip", "IpAddr", "V4"]; +pub const IPADDR_V6: [&str; 5] = ["std", "net", "ip", "IpAddr", "V6"]; +pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"]; #[cfg(feature = "internal-lints")] pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"]; #[cfg(feature = "internal-lints")] @@ -117,7 +138,6 @@ pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"]; pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"]; pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"]; pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"]; -pub const REPEAT: [&str; 3] = ["core", "iter", "repeat"]; pub const RESULT: [&str; 3] = ["core", "result", "Result"]; pub const RESULT_ERR: [&str; 4] = ["core", "result", "Result", "Err"]; pub const RESULT_OK: [&str; 4] = ["core", "result", "Result", "Ok"]; @@ -131,7 +151,7 @@ pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "", "into_vec pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"]; pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"]; pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"]; -pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"]; +pub const CONVERT_IDENTITY: [&str; 3] = ["core", "convert", "identity"]; pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"]; pub const STD_MEM_TRANSMUTE: [&str; 3] = ["std", "mem", "transmute"]; pub const STD_PTR_NULL: [&str; 3] = ["std", "ptr", "null"]; @@ -165,6 +185,7 @@ pub const VEC_DEQUE: [&str; 4] = ["alloc", "collections", "vec_deque", "VecDeque pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"]; pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; +pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"]; pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"]; pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"]; pub const WRITE_BYTES: [&str; 3] = ["core", "intrinsics", "write_bytes"]; diff --git a/doc/adding_lints.md b/doc/adding_lints.md index 99b86953d51a..50f0d724016f 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -625,7 +625,7 @@ in the following steps: Here are some pointers to things you are likely going to need for every lint: * [Clippy utils][utils] - Various helper functions. Maybe the function you need - is already in here (`implements_trait`, `match_path`, `snippet`, etc) + is already in here (`implements_trait`, `match_def_path`, `snippet`, etc) * [Clippy diagnostics][diagnostics] * [The `if_chain` macro][if_chain] * [`from_expansion`][from_expansion] and [`in_external_macro`][in_external_macro] diff --git a/tests/ui-internal/collapsible_span_lint_calls.fixed b/tests/ui-internal/collapsible_span_lint_calls.fixed index e588c23345e2..7764cc8da786 100644 --- a/tests/ui-internal/collapsible_span_lint_calls.fixed +++ b/tests/ui-internal/collapsible_span_lint_calls.fixed @@ -2,58 +2,18 @@ #![deny(clippy::internal)] #![feature(rustc_private)] +extern crate clippy_utils; extern crate rustc_ast; extern crate rustc_errors; extern crate rustc_lint; extern crate rustc_session; extern crate rustc_span; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then}; use rustc_ast::ast::Expr; -use rustc_errors::{Applicability, DiagnosticBuilder}; -use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext}; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; - -#[allow(unused_variables)] -pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F) -where - F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>), -{ -} - -#[allow(unused_variables)] -fn span_lint_and_help<'a, T: LintContext>( - cx: &'a T, - lint: &'static Lint, - span: Span, - msg: &str, - option_span: Option, - help: &str, -) { -} - -#[allow(unused_variables)] -fn span_lint_and_note<'a, T: LintContext>( - cx: &'a T, - lint: &'static Lint, - span: Span, - msg: &str, - note_span: Option, - note: &str, -) { -} - -#[allow(unused_variables)] -fn span_lint_and_sugg<'a, T: LintContext>( - cx: &'a T, - lint: &'static Lint, - sp: Span, - msg: &str, - help: &str, - sugg: String, - applicability: Applicability, -) { -} declare_tool_lint! { pub clippy::TEST_LINT, diff --git a/tests/ui-internal/collapsible_span_lint_calls.rs b/tests/ui-internal/collapsible_span_lint_calls.rs index d5dd3bb562b4..bdd296db8320 100644 --- a/tests/ui-internal/collapsible_span_lint_calls.rs +++ b/tests/ui-internal/collapsible_span_lint_calls.rs @@ -2,58 +2,18 @@ #![deny(clippy::internal)] #![feature(rustc_private)] +extern crate clippy_utils; extern crate rustc_ast; extern crate rustc_errors; extern crate rustc_lint; extern crate rustc_session; extern crate rustc_span; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then}; use rustc_ast::ast::Expr; -use rustc_errors::{Applicability, DiagnosticBuilder}; -use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext}; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Span; - -#[allow(unused_variables)] -pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F) -where - F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>), -{ -} - -#[allow(unused_variables)] -fn span_lint_and_help<'a, T: LintContext>( - cx: &'a T, - lint: &'static Lint, - span: Span, - msg: &str, - option_span: Option, - help: &str, -) { -} - -#[allow(unused_variables)] -fn span_lint_and_note<'a, T: LintContext>( - cx: &'a T, - lint: &'static Lint, - span: Span, - msg: &str, - note_span: Option, - note: &str, -) { -} - -#[allow(unused_variables)] -fn span_lint_and_sugg<'a, T: LintContext>( - cx: &'a T, - lint: &'static Lint, - sp: Span, - msg: &str, - help: &str, - sugg: String, - applicability: Applicability, -) { -} declare_tool_lint! { pub clippy::TEST_LINT, diff --git a/tests/ui-internal/collapsible_span_lint_calls.stderr b/tests/ui-internal/collapsible_span_lint_calls.stderr index 874d4a9f255c..0632b0385773 100644 --- a/tests/ui-internal/collapsible_span_lint_calls.stderr +++ b/tests/ui-internal/collapsible_span_lint_calls.stderr @@ -1,5 +1,5 @@ error: this call is collapsible - --> $DIR/collapsible_span_lint_calls.rs:75:9 + --> $DIR/collapsible_span_lint_calls.rs:35:9 | LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { LL | | db.span_suggestion(expr.span, help_msg, sugg.to_string(), Applicability::MachineApplicable); @@ -14,7 +14,7 @@ LL | #![deny(clippy::internal)] = note: `#[deny(clippy::collapsible_span_lint_calls)]` implied by `#[deny(clippy::internal)]` error: this call is collapsible - --> $DIR/collapsible_span_lint_calls.rs:78:9 + --> $DIR/collapsible_span_lint_calls.rs:38:9 | LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { LL | | db.span_help(expr.span, help_msg); @@ -22,7 +22,7 @@ LL | | }); | |__________^ help: collapse into: `span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg)` error: this call is collapsible - --> $DIR/collapsible_span_lint_calls.rs:81:9 + --> $DIR/collapsible_span_lint_calls.rs:41:9 | LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { LL | | db.help(help_msg); @@ -30,7 +30,7 @@ LL | | }); | |__________^ help: collapse into: `span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg)` error: this call is collspible - --> $DIR/collapsible_span_lint_calls.rs:84:9 + --> $DIR/collapsible_span_lint_calls.rs:44:9 | LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { LL | | db.span_note(expr.span, note_msg); @@ -38,7 +38,7 @@ LL | | }); | |__________^ help: collapse into: `span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg)` error: this call is collspible - --> $DIR/collapsible_span_lint_calls.rs:87:9 + --> $DIR/collapsible_span_lint_calls.rs:47:9 | LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { LL | | db.note(note_msg); diff --git a/tests/ui-internal/match_type_on_diag_item.rs b/tests/ui-internal/match_type_on_diag_item.rs index fe950b0aa7c7..29977db0b864 100644 --- a/tests/ui-internal/match_type_on_diag_item.rs +++ b/tests/ui-internal/match_type_on_diag_item.rs @@ -1,29 +1,18 @@ #![deny(clippy::internal)] #![feature(rustc_private)] +extern crate clippy_utils; extern crate rustc_hir; extern crate rustc_lint; extern crate rustc_middle; + #[macro_use] extern crate rustc_session; +use clippy_utils::{paths, ty::match_type}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; -mod paths { - pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"]; -} - -mod utils { - use super::*; - - pub fn match_type(_cx: &LateContext<'_>, _ty: Ty<'_>, _path: &[&str]) -> bool { - false - } -} - -use utils::match_type; - declare_lint! { pub TEST_LINT, Warn, @@ -43,7 +32,7 @@ impl<'tcx> LateLintPass<'tcx> for Pass { let _ = match_type(cx, ty, &["core", "result", "Result"]); let rc_path = &["alloc", "rc", "Rc"]; - let _ = utils::match_type(cx, ty, rc_path); + let _ = clippy_utils::ty::match_type(cx, ty, rc_path); } } diff --git a/tests/ui-internal/match_type_on_diag_item.stderr b/tests/ui-internal/match_type_on_diag_item.stderr index 82465dbaf6ec..714729605658 100644 --- a/tests/ui-internal/match_type_on_diag_item.stderr +++ b/tests/ui-internal/match_type_on_diag_item.stderr @@ -1,8 +1,8 @@ -error: usage of `utils::match_type()` on a type diagnostic item - --> $DIR/match_type_on_diag_item.rs:41:17 +error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item + --> $DIR/match_type_on_diag_item.rs:31:17 | -LL | let _ = match_type(cx, ty, &paths::VEC); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::vec_type)` +LL | let _ = match_type(cx, ty, &OPTION); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::option_type)` | note: the lint level is defined here --> $DIR/match_type_on_diag_item.rs:1:9 @@ -11,23 +11,17 @@ LL | #![deny(clippy::internal)] | ^^^^^^^^^^^^^^^^ = note: `#[deny(clippy::match_type_on_diagnostic_item)]` implied by `#[deny(clippy::internal)]` -error: usage of `utils::match_type()` on a type diagnostic item - --> $DIR/match_type_on_diag_item.rs:42:17 - | -LL | let _ = match_type(cx, ty, &OPTION); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::option_type)` - -error: usage of `utils::match_type()` on a type diagnostic item - --> $DIR/match_type_on_diag_item.rs:43:17 +error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item + --> $DIR/match_type_on_diag_item.rs:32:17 | LL | let _ = match_type(cx, ty, &["core", "result", "Result"]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::result_type)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::result_type)` -error: usage of `utils::match_type()` on a type diagnostic item - --> $DIR/match_type_on_diag_item.rs:46:17 +error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item + --> $DIR/match_type_on_diag_item.rs:35:17 | -LL | let _ = utils::match_type(cx, ty, rc_path); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::Rc)` +LL | let _ = clippy_utils::ty::match_type(cx, ty, rc_path); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Rc)` -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/repl_uninit.stderr b/tests/ui/repl_uninit.stderr index 09468eeaea4b..4b9d1242da85 100644 --- a/tests/ui/repl_uninit.stderr +++ b/tests/ui/repl_uninit.stderr @@ -12,6 +12,14 @@ error: replacing with `mem::MaybeUninit::uninit().assume_init()` LL | let taken_v = mem::replace(&mut v, mem::MaybeUninit::uninit().assume_init()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::ptr::read(&mut v)` +error: this call for this type may be undefined behavior + --> $DIR/repl_uninit.rs:21:44 + | +LL | let taken_v = mem::replace(&mut v, mem::MaybeUninit::uninit().assume_init()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::uninit-assumed-init` implied by `-D warnings` + error: replacing with `mem::zeroed()` --> $DIR/repl_uninit.rs:27:23 | @@ -26,5 +34,5 @@ error: replacing with `mem::uninitialized()` LL | let taken_u = unsafe { mem::replace(uref, mem::uninitialized()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::ptr::read(uref)` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors