diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 12f91d7bf63..b9be1f7e60c 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -12,12 +12,13 @@ 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}; +use rustc_span::symbol::sym; use crate::consts::{constant, Constant}; use crate::utils::sugg::Sugg; use crate::utils::{ - get_item_name, get_parent_expr, higher, implements_trait, in_constant, is_integer_const, iter_input_pats, - last_path_segment, match_qpath, match_trait_method, paths, snippet, snippet_opt, span_lint, span_lint_and_sugg, + get_item_name, get_parent_expr, higher, implements_trait, in_constant, is_diagnostic_assoc_item, is_integer_const, + iter_input_pats, last_path_segment, match_qpath, snippet, snippet_opt, span_lint, span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then, unsext, SpanlessEq, }; @@ -554,11 +555,16 @@ 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.typeck_results().expr_ty(&args[0]), snippet(cx, args[0].span, "..")) - } else { - return; - } + 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); + then { + (cx.typeck_results().expr_ty(&args[0]), snippet(cx, args[0].span, "..")) + } else { + return; + } + ) }, ExprKind::Call(ref path, ref v) if v.len() == 1 => { if let ExprKind::Path(ref path) = path.kind { diff --git a/clippy_lints/src/path_buf_push_overwrite.rs b/clippy_lints/src/path_buf_push_overwrite.rs index 6eeb031d383..4a7b0ad07aa 100644 --- a/clippy_lints/src/path_buf_push_overwrite.rs +++ b/clippy_lints/src/path_buf_push_overwrite.rs @@ -1,10 +1,11 @@ -use crate::utils::{match_type, paths, span_lint_and_sugg}; +use crate::utils::{is_type_diagnostic_item, span_lint_and_sugg}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::sym; use std::path::{Component, Path}; declare_clippy_lint! { @@ -46,7 +47,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, cx.typeck_results().expr_ty(&args[0]).peel_refs(), &paths::PATH_BUF); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), sym::PathBuf); 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/ptr.rs b/clippy_lints/src/ptr.rs index 5474fdf30bf..6ea2d8b06d8 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -233,7 +233,7 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: }, ); } - } else if match_type(cx, ty, &paths::PATH_BUF) { + } else if is_type_diagnostic_item(cx, ty, sym::PathBuf) { if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_path_buf()"), ("as_path", "")]) { span_lint_and_then( cx, diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index d74ba10ac50..99263bf8b5c 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -1,6 +1,6 @@ use crate::utils::{ - fn_has_unsatisfiable_preds, has_drop, is_copy, is_type_diagnostic_item, match_def_path, match_type, paths, - snippet_opt, span_lint_hir, span_lint_hir_and_then, walk_ptrs_ty_depth, + fn_has_unsatisfiable_preds, has_drop, is_copy, is_type_diagnostic_item, match_def_path, paths, snippet_opt, + span_lint_hir, span_lint_hir_and_then, walk_ptrs_ty_depth, }; use if_chain::if_chain; use rustc_data_structures::{fx::FxHashMap, transitive_relation::TransitiveRelation}; @@ -166,8 +166,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { is_call_with_ref_arg(cx, mir, &pred_terminator.kind); if res == cloned; if cx.tcx.is_diagnostic_item(sym::deref_method, pred_fn_def_id); - if match_type(cx, pred_arg_ty, &paths::PATH_BUF) - || match_type(cx, pred_arg_ty, &paths::OS_STRING); + if is_type_diagnostic_item(cx, pred_arg_ty, sym::PathBuf) + || is_type_diagnostic_item(cx, pred_arg_ty, sym::OsString); then { (pred_arg, res) } else { diff --git a/clippy_lints/src/to_string_in_display.rs b/clippy_lints/src/to_string_in_display.rs index fdd105e6246..84ec2aa18ab 100644 --- a/clippy_lints/src/to_string_in_display.rs +++ b/clippy_lints/src/to_string_in_display.rs @@ -1,8 +1,9 @@ -use crate::utils::{match_def_path, match_trait_method, path_to_local_id, paths, span_lint}; +use crate::utils::{is_diagnostic_assoc_item, match_def_path, path_to_local_id, paths, span_lint}; use if_chain::if_chain; use rustc_hir::{Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::symbol::sym; declare_clippy_lint! { /// **What it does:** Checks for uses of `to_string()` in `Display` traits. @@ -92,7 +93,8 @@ impl LateLintPass<'_> for ToStringInDisplay { if let Some(self_hir_id) = self.self_hir_id; if let ExprKind::MethodCall(ref path, _, args, _) = expr.kind; if path.ident.name == sym!(to_string); - if match_trait_method(cx, expr, &paths::TO_STRING); + if 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 path_to_local_id(&args[0], self_hir_id); then { span_lint( diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index c420be26fc6..ce201b956d8 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -23,7 +23,7 @@ use rustc_semver::RustcVersion; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::Span; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::sym; use rustc_target::abi::LayoutOf; use rustc_target::spec::abi::Abi; use rustc_typeck::hir_ty_to_ty; @@ -33,10 +33,10 @@ use crate::utils::paths; use crate::utils::sugg::Sugg; use crate::utils::{ clip, comparisons, differing_macro_contexts, get_qpath_generic_tys, higher, in_constant, indent_of, int_bits, - is_hir_ty_cfg_dependant, is_type_diagnostic_item, last_path_segment, match_def_path, match_path, meets_msrv, - method_chain_args, multispan_sugg, numeric_literal::NumericLiteral, reindent_multiline, sext, snippet, snippet_opt, - snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, - span_lint_and_then, unsext, + is_hir_ty_cfg_dependant, is_ty_param_diagnostic_item, is_ty_param_lang_item, is_type_diagnostic_item, + last_path_segment, match_def_path, match_path, meets_msrv, method_chain_args, multispan_sugg, + numeric_literal::NumericLiteral, reindent_multiline, sext, snippet, snippet_opt, snippet_with_applicability, + snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext, }; declare_clippy_lint! { @@ -287,51 +287,12 @@ impl<'tcx> LateLintPass<'tcx> for Types { } } -/// Checks if the first type parameter is a lang item. -fn is_ty_param_lang_item(cx: &LateContext<'_>, qpath: &QPath<'tcx>, item: LangItem) -> Option<&'tcx hir::Ty<'tcx>> { - let ty = get_qpath_generic_tys(qpath).next()?; - - if let TyKind::Path(qpath) = &ty.kind { - cx.qpath_res(qpath, ty.hir_id) - .opt_def_id() - .and_then(|id| (cx.tcx.lang_items().require(item) == Ok(id)).then(|| ty)) - } else { - None - } -} - -/// Checks if the first type parameter is a diagnostic item. -fn is_ty_param_diagnostic_item(cx: &LateContext<'_>, qpath: &QPath<'tcx>, item: Symbol) -> Option<&'tcx hir::Ty<'tcx>> { - let ty = get_qpath_generic_tys(qpath).next()?; - - if let TyKind::Path(qpath) = &ty.kind { - cx.qpath_res(qpath, ty.hir_id) - .opt_def_id() - .and_then(|id| cx.tcx.is_diagnostic_item(item, id).then(|| ty)) - } else { - None - } -} - -/// Checks if the first type parameter is a given item. -fn is_ty_param_path(cx: &LateContext<'_>, qpath: &QPath<'tcx>, path: &[&str]) -> Option<&'tcx hir::Ty<'tcx>> { - let ty = get_qpath_generic_tys(qpath).next()?; - - if let TyKind::Path(qpath) = &ty.kind { - cx.qpath_res(qpath, ty.hir_id) - .opt_def_id() - .and_then(|id| match_def_path(cx, id, path).then(|| ty)) - } else { - None - } -} - fn match_buffer_type(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> { if is_ty_param_diagnostic_item(cx, qpath, sym::string_type).is_some() { Some("str") - } else if is_ty_param_path(cx, qpath, &paths::OS_STRING).is_some() { + } else if is_ty_param_diagnostic_item(cx, qpath, sym::OsString).is_some() { Some("std::ffi::OsStr") - } else if is_ty_param_path(cx, qpath, &paths::PATH_BUF).is_some() { + } else if is_ty_param_diagnostic_item(cx, qpath, sym::PathBuf).is_some() { Some("std::path::Path") } else { None diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 6582ad71707..3845667802d 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -64,8 +64,8 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::Node; use rustc_hir::{ def, Arm, Block, Body, Constness, Crate, Expr, ExprKind, FnDecl, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, - Item, ItemKind, MatchSource, Param, Pat, PatKind, Path, PathSegment, QPath, TraitItem, TraitItemKind, TraitRef, - TyKind, Unsafety, + Item, ItemKind, LangItem, MatchSource, Param, Pat, PatKind, Path, PathSegment, QPath, TraitItem, TraitItemKind, + TraitRef, TyKind, Unsafety, }; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, Level, Lint, LintContext}; @@ -232,6 +232,36 @@ pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangI } } +/// Checks if the first type parameter is a lang item. +pub fn is_ty_param_lang_item(cx: &LateContext<'_>, qpath: &QPath<'tcx>, item: LangItem) -> Option<&'tcx hir::Ty<'tcx>> { + let ty = get_qpath_generic_tys(qpath).next()?; + + if let TyKind::Path(qpath) = &ty.kind { + cx.qpath_res(qpath, ty.hir_id) + .opt_def_id() + .and_then(|id| (cx.tcx.lang_items().require(item) == Ok(id)).then(|| ty)) + } else { + None + } +} + +/// Checks if the first type parameter is a diagnostic item. +pub fn is_ty_param_diagnostic_item( + cx: &LateContext<'_>, + qpath: &QPath<'tcx>, + item: Symbol, +) -> Option<&'tcx hir::Ty<'tcx>> { + let ty = get_qpath_generic_tys(qpath).next()?; + + if let TyKind::Path(qpath) = &ty.kind { + cx.qpath_res(qpath, ty.hir_id) + .opt_def_id() + .and_then(|id| cx.tcx.is_diagnostic_item(item, id).then(|| ty)) + } else { + None + } +} + /// 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.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 14c38459dde..3e79646da3f 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -84,7 +84,6 @@ pub const OPTION: [&str; 3] = ["core", "option", "Option"]; pub const OPTION_NONE: [&str; 4] = ["core", "option", "Option", "None"]; pub const OPTION_SOME: [&str; 4] = ["core", "option", "Option", "Some"]; pub const ORD: [&str; 3] = ["core", "cmp", "Ord"]; -pub const OS_STRING: [&str; 4] = ["std", "ffi", "os_str", "OsString"]; pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"]; pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"]; pub(super) const PANICKING_PANIC: [&str; 3] = ["core", "panicking", "panic"]; @@ -155,9 +154,7 @@ pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"]; #[cfg(feature = "internal-lints")] pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; -pub const TO_OWNED: [&str; 3] = ["alloc", "borrow", "ToOwned"]; pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"]; -pub const TO_STRING: [&str; 3] = ["alloc", "string", "ToString"]; pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"]; pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"]; pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"];