From 76bd5d232c767dbdab63005eca07a9563982e9dd Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 12 Apr 2021 18:01:32 -0500 Subject: [PATCH] Refactor diagnostic item methods --- clippy_lints/src/mem_replace.rs | 21 +++++++------- clippy_lints/src/methods/implicit_clone.rs | 28 ++++++++++++------- clippy_lints/src/methods/mod.rs | 7 ++--- clippy_lints/src/misc.rs | 6 ++-- clippy_lints/src/to_string_in_display.rs | 4 +-- clippy_utils/src/lib.rs | 32 ++++++++++++---------- 6 files changed, 53 insertions(+), 45 deletions(-) diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 1f521ec6090..ec60bffe955 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_with_applicability}; -use clippy_utils::{in_macro, match_def_path, meets_msrv, paths}; -use clippy_utils::{is_diagnostic_assoc_item, is_lang_ctor}; +use clippy_utils::{in_macro, is_diag_trait_item, is_lang_ctor, match_def_path, meets_msrv, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; @@ -211,17 +210,17 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath< sym::BinaryHeap, ]; - if std_types_symbols - .iter() - .any(|symbol| is_diagnostic_assoc_item(cx, def_id, *symbol)) - { - if let QPath::TypeRelative(_, method) = path { - if method.ident.name == sym::new { - return true; + if let QPath::TypeRelative(_, method) = path { + if method.ident.name == sym::new { + if let Some(impl_did) = cx.tcx.impl_of_method(def_id) { + if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() { + return std_types_symbols + .iter() + .any(|&symbol| cx.tcx.is_diagnostic_item(symbol, adt.did)); + } } } } - false } @@ -231,7 +230,7 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr< if !in_external_macro(cx.tcx.sess, expr_span); if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind; if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); - if is_diagnostic_assoc_item(cx, repl_def_id, sym::Default) + if is_diag_trait_item(cx, repl_def_id, sym::Default) || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath); then { diff --git a/clippy_lints/src/methods/implicit_clone.rs b/clippy_lints/src/methods/implicit_clone.rs index 1211e2f2bf7..81c42de145f 100644 --- a/clippy_lints/src/methods/implicit_clone.rs +++ b/clippy_lints/src/methods/implicit_clone.rs @@ -1,28 +1,36 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::{is_diag_item_method, is_diag_trait_item}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::ExprKind; use rustc_lint::LateContext; use rustc_middle::ty::TyS; -use rustc_span::symbol::Symbol; +use rustc_span::{sym, Span}; use super::IMPLICIT_CLONE; -use clippy_utils::is_diagnostic_assoc_item; -pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, trait_diagnostic: Symbol) { +pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, span: Span) { if_chain! { - if let ExprKind::MethodCall(method_path, _, [arg], _) = &expr.kind; + if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if match method_name { + "to_os_string" => is_diag_item_method(cx, method_def_id, sym::OsStr), + "to_owned" => is_diag_trait_item(cx, method_def_id, sym::ToOwned), + "to_path_buf" => is_diag_item_method(cx, method_def_id, sym::Path), + "to_vec" => cx.tcx.impl_of_method(method_def_id) + .map(|impl_did| Some(impl_did) == cx.tcx.lang_items().slice_alloc_impl()) + == Some(true), + _ => false, + }; let return_type = cx.typeck_results().expr_ty(expr); - let input_type = cx.typeck_results().expr_ty(arg).peel_refs(); - if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + let input_type = cx.typeck_results().expr_ty(recv).peel_refs(); if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did)); if TyS::same_type(return_type, input_type); - if is_diagnostic_assoc_item(cx, expr_def_id, trait_diagnostic); then { span_lint_and_sugg( - cx,IMPLICIT_CLONE,method_path.ident.span, - &format!("implicitly cloning a `{}` by calling `{}` on its dereferenced type", ty_name, method_path.ident.name), + cx, + IMPLICIT_CLONE, + span, + &format!("implicitly cloning a `{}` by calling `{}` on its dereferenced type", ty_name, method_name), "consider using", "clone".to_string(), Applicability::MachineApplicable diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index fc18849b07c..b2faaef0786 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1987,10 +1987,9 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio } }, ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), - ("to_os_string", []) => implicit_clone::check(cx, expr, sym::OsStr), - ("to_owned", []) => implicit_clone::check(cx, expr, sym::ToOwned), - ("to_path_buf", []) => implicit_clone::check(cx, expr, sym::Path), - ("to_vec", []) => implicit_clone::check(cx, expr, sym::slice), + ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => { + implicit_clone::check(cx, name, expr, recv, span); + }, ("unwrap", []) => match method_call!(recv) { Some(("get", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, false), Some(("get_mut", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, true), diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index afced5a5ce5..d156c1d5bf4 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -20,7 +20,7 @@ use rustc_span::symbol::sym; use crate::consts::{constant, Constant}; use clippy_utils::sugg::Sugg; use clippy_utils::{ - get_item_name, get_parent_expr, higher, in_constant, is_diagnostic_assoc_item, is_integer_const, iter_input_pats, + get_item_name, get_parent_expr, higher, in_constant, is_diag_trait_item, is_integer_const, iter_input_pats, last_path_segment, match_qpath, unsext, SpanlessEq, }; @@ -555,8 +555,8 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: ExprKind::MethodCall(.., args, _) if args.len() == 1 => { if_chain!( if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if is_diagnostic_assoc_item(cx, expr_def_id, sym::ToString) - || is_diagnostic_assoc_item(cx, expr_def_id, sym::ToOwned); + if is_diag_trait_item(cx, expr_def_id, sym::ToString) + || is_diag_trait_item(cx, expr_def_id, sym::ToOwned); then { (cx.typeck_results().expr_ty(&args[0]), snippet(cx, args[0].span, "..")) } else { diff --git a/clippy_lints/src/to_string_in_display.rs b/clippy_lints/src/to_string_in_display.rs index ae05a8da37b..4fb297ac6c6 100644 --- a/clippy_lints/src/to_string_in_display.rs +++ b/clippy_lints/src/to_string_in_display.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{is_diagnostic_assoc_item, match_def_path, path_to_local_id, paths}; +use clippy_utils::{is_diag_trait_item, match_def_path, path_to_local_id, paths}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -95,7 +95,7 @@ impl LateLintPass<'_> for ToStringInDisplay { if let ExprKind::MethodCall(path, _, args, _) = expr.kind; if path.ident.name == sym!(to_string); if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if is_diagnostic_assoc_item(cx, expr_def_id, sym::ToString); + if is_diag_trait_item(cx, expr_def_id, sym::ToString); if path_to_local_id(&args[0], self_hir_id); then { span_lint( diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index e99ffbe269b..ec140463a8a 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -293,27 +293,29 @@ pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) trt_id.map_or(false, |trt_id| match_def_path(cx, trt_id, path)) } -/// Checks if the method call given in `def_id` belongs to a trait or other container with a given -/// diagnostic item -pub fn is_diagnostic_assoc_item(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool { - cx.tcx - .opt_associated_item(def_id) - .and_then(|associated_item| match associated_item.container { - rustc_ty::TraitContainer(assoc_def_id) => Some(assoc_def_id), - rustc_ty::ImplContainer(assoc_def_id) => match cx.tcx.type_of(assoc_def_id).kind() { - rustc_ty::Adt(adt, _) => Some(adt.did), - rustc_ty::Slice(_) => cx.tcx.get_diagnostic_item(sym::slice), // this isn't perfect but it works - _ => None, - }, - }) - .map_or(false, |assoc_def_id| cx.tcx.is_diagnostic_item(diag_item, assoc_def_id)) +/// Checks if a method is defined in an impl of a diagnostic item +pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool { + if let Some(impl_did) = cx.tcx.impl_of_method(def_id) { + if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def() { + return cx.tcx.is_diagnostic_item(diag_item, adt.did); + } + } + false +} + +/// Checks if a method is in a diagnostic item trait +pub fn is_diag_trait_item(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool { + if let Some(trait_did) = cx.tcx.trait_of_item(def_id) { + return cx.tcx.is_diagnostic_item(diag_item, trait_did); + } + false } /// Checks if the method call given in `expr` belongs to the given trait. pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool { cx.typeck_results() .type_dependent_def_id(expr.hir_id) - .map_or(false, |did| is_diagnostic_assoc_item(cx, did, diag_item)) + .map_or(false, |did| is_diag_trait_item(cx, did, diag_item)) } /// Checks if an expression references a variable of the given name.