From cc975929c528d0883d7553c53dc47030c08d01e0 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Wed, 5 Jan 2022 20:36:22 -0600 Subject: [PATCH 01/10] Rename path_to_res to def_path_res --- clippy_lints/src/disallowed_methods.rs | 2 +- clippy_lints/src/disallowed_types.rs | 2 +- clippy_lints/src/missing_enforced_import_rename.rs | 2 +- clippy_lints/src/utils/internal_lints.rs | 10 +++++----- clippy_utils/src/lib.rs | 7 ++++--- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index 73c00d97020b..4c12202c84ab 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { fn check_crate(&mut self, cx: &LateContext<'_>) { for (index, conf) in self.conf_disallowed.iter().enumerate() { let segs: Vec<_> = conf.path().split("::").collect(); - if let Res::Def(_, id) = clippy_utils::path_to_res(cx, &segs) { + if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs) { self.disallowed.insert(id, index); } } diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs index ea4b49b46fe9..14f89edce615 100644 --- a/clippy_lints/src/disallowed_types.rs +++ b/clippy_lints/src/disallowed_types.rs @@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes { ), }; let segs: Vec<_> = path.split("::").collect(); - match clippy_utils::path_to_res(cx, &segs) { + match clippy_utils::def_path_res(cx, &segs) { Res::Def(_, id) => { self.def_ids.insert(id, reason); }, diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index 566e15ab2a6d..3d0a23822838 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -58,7 +58,7 @@ impl_lint_pass!(ImportRename => [MISSING_ENFORCED_IMPORT_RENAMES]); impl LateLintPass<'_> for ImportRename { fn check_crate(&mut self, cx: &LateContext<'_>) { for Rename { path, rename } in &self.conf_renames { - if let Res::Def(_, id) = clippy_utils::path_to_res(cx, &path.split("::").collect::>()) { + if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &path.split("::").collect::>()) { self.renames.insert(id, Symbol::intern(rename)); } } diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index f170ff69154b..dc0f515bfe5c 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -4,8 +4,8 @@ use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::snippet; use clippy_utils::ty::match_type; use clippy_utils::{ - higher, is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_def_path, method_calls, - path_to_res, paths, peel_blocks_with_stmt, SpanlessEq, + def_path_res, higher, is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_def_path, + method_calls, paths, peel_blocks_with_stmt, SpanlessEq, }; use if_chain::if_chain; use rustc_ast as ast; @@ -844,7 +844,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem { // Extract the path to the matched type if let Some(segments) = path_to_matched_type(cx, ty_path); let segments: Vec<&str> = segments.iter().map(Symbol::as_str).collect(); - if let Some(ty_did) = path_to_res(cx, &segments[..]).opt_def_id(); + if let Some(ty_did) = def_path_res(cx, &segments[..]).opt_def_id(); // Check if the matched type is a diagnostic item if let Some(item_name) = cx.tcx.get_diagnostic_name(ty_did); then { @@ -917,7 +917,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option, path: &[&str]) -> bool { - if path_to_res(cx, path) != Res::Err { + if def_path_res(cx, path) != Res::Err { return true; } @@ -999,7 +999,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { } for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] { - if let Some(def_id) = path_to_res(cx, module).opt_def_id() { + if let Some(def_id) = def_path_res(cx, module).opt_def_id() { for item in cx.tcx.module_children(def_id).iter() { if_chain! { if let Res::Def(DefKind::Const, item_def_id) = item.res; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index a2f1f4696513..28bca902e190 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -497,8 +497,9 @@ pub fn path_to_local_id(expr: &Expr<'_>, id: HirId) -> bool { path_to_local(expr) == Some(id) } -/// Gets the definition associated to a path. -pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res { +/// Resolves a def path like `std::vec::Vec`. +/// This function is expensive and should be used sparingly. +pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res { macro_rules! try_res { ($e:expr) => { match $e { @@ -574,7 +575,7 @@ pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res { /// Convenience function to get the `DefId` of a trait by path. /// It could be a trait or trait alias. pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option { - match path_to_res(cx, path) { + match def_path_res(cx, path) { Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id), _ => None, } From bea09a2329676e48ea9f780c47e27d653417a4e3 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 4 Jan 2022 17:24:23 -0600 Subject: [PATCH 02/10] Add path_def_id util --- clippy_utils/src/lib.rs | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 28bca902e190..8cc4f0449e31 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -497,6 +497,43 @@ pub fn path_to_local_id(expr: &Expr<'_>, id: HirId) -> bool { path_to_local(expr) == Some(id) } +pub trait MaybePath<'hir> { + fn hir_id(&self) -> HirId; + fn qpath_opt(&self) -> Option<&QPath<'hir>>; +} + +macro_rules! maybe_path { + ($ty:ident, $kind:ident) => { + impl<'hir> MaybePath<'hir> for hir::$ty<'hir> { + fn hir_id(&self) -> HirId { + self.hir_id + } + fn qpath_opt(&self) -> Option<&QPath<'hir>> { + match &self.kind { + hir::$kind::Path(qpath) => Some(qpath), + _ => None, + } + } + } + }; +} +maybe_path!(Expr, ExprKind); +maybe_path!(Pat, PatKind); +maybe_path!(Ty, TyKind); + +/// If `maybe_path` is a path node, resolves it, otherwise returns `Res::Err` +pub fn path_res<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>) -> Res { + match maybe_path.qpath_opt() { + None => Res::Err, + Some(qpath) => cx.qpath_res(qpath, maybe_path.hir_id()), + } +} + +/// If `maybe_path` is a path node which resolves to an item, retrieves the item ID +pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>) -> Option { + path_res(cx, maybe_path).opt_def_id() +} + /// Resolves a def path like `std::vec::Vec`. /// This function is expensive and should be used sparingly. pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res { From 20781f195d205dcc3fa244a659dfc5b3547a87d3 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 17 Jan 2022 12:57:45 -0600 Subject: [PATCH 03/10] Rename qpath_generic_tys --- clippy_lints/src/types/rc_buffer.rs | 6 +++--- clippy_lints/src/types/redundant_allocation.rs | 4 ++-- clippy_utils/src/lib.rs | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/types/rc_buffer.rs b/clippy_lints/src/types/rc_buffer.rs index 31c4abdfc95e..0a2df7d21883 100644 --- a/clippy_lints/src/types/rc_buffer.rs +++ b/clippy_lints/src/types/rc_buffer.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{get_qpath_generic_tys, is_ty_param_diagnostic_item}; +use clippy_utils::{is_ty_param_diagnostic_item, qpath_generic_tys}; use rustc_errors::Applicability; use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind}; use rustc_lint::LateContext; @@ -25,7 +25,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ TyKind::Path(qpath) => qpath, _ => return false, }; - let inner_span = match get_qpath_generic_tys(qpath).next() { + let inner_span = match qpath_generic_tys(qpath).next() { Some(ty) => ty.span, None => return false, }; @@ -60,7 +60,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ TyKind::Path(qpath) => qpath, _ => return false, }; - let inner_span = match get_qpath_generic_tys(qpath).next() { + let inner_span = match qpath_generic_tys(qpath).next() { Some(ty) => ty.span, None => return false, }; diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs index ac7bdd6a1ebe..8638197a5842 100644 --- a/clippy_lints/src/types/redundant_allocation.rs +++ b/clippy_lints/src/types/redundant_allocation.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{snippet, snippet_with_applicability}; -use clippy_utils::{get_qpath_generic_tys, is_ty_param_diagnostic_item, is_ty_param_lang_item}; +use clippy_utils::{is_ty_param_diagnostic_item, is_ty_param_lang_item, qpath_generic_tys}; use rustc_errors::Applicability; use rustc_hir::{self as hir, def_id::DefId, LangItem, QPath, TyKind}; use rustc_lint::LateContext; @@ -53,7 +53,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ TyKind::Path(inner_qpath) => inner_qpath, _ => return false, }; - let inner_span = match get_qpath_generic_tys(inner_qpath).next() { + let inner_span = match qpath_generic_tys(inner_qpath).next() { Some(ty) => { // Box> is smaller than Box because of wide pointers if matches!(ty.kind, TyKind::TraitObject(..)) { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 8cc4f0449e31..64634c64602f 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -268,7 +268,7 @@ pub fn is_ty_param_lang_item<'tcx>( qpath: &QPath<'tcx>, item: LangItem, ) -> Option<&'tcx hir::Ty<'tcx>> { - let ty = get_qpath_generic_tys(qpath).next()?; + let ty = qpath_generic_tys(qpath).next()?; if let TyKind::Path(qpath) = &ty.kind { cx.qpath_res(qpath, ty.hir_id) @@ -288,7 +288,7 @@ pub fn is_ty_param_diagnostic_item<'tcx>( qpath: &QPath<'tcx>, item: Symbol, ) -> Option<&'tcx hir::Ty<'tcx>> { - let ty = get_qpath_generic_tys(qpath).next()?; + let ty = qpath_generic_tys(qpath).next()?; if let TyKind::Path(qpath) = &ty.kind { cx.qpath_res(qpath, ty.hir_id) @@ -368,7 +368,7 @@ pub fn get_qpath_generics<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx GenericArgs< } } -pub fn get_qpath_generic_tys<'tcx>(path: &QPath<'tcx>) -> impl Iterator> { +pub fn qpath_generic_tys<'tcx>(path: &QPath<'tcx>) -> impl Iterator> { get_qpath_generics(path) .map_or([].as_ref(), |a| a.args) .iter() From 145d7fc5298cec0995bdc4e71d09d275fcbcdcdb Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 17 Jan 2022 13:39:45 -0600 Subject: [PATCH 04/10] Factor out get_qpath_generics --- clippy_utils/src/lib.rs | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 64634c64602f..82d502386668 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -77,9 +77,9 @@ use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk}; use rustc_hir::{ def, lang_items, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr, - ExprKind, FnDecl, ForeignItem, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, - Local, MatchSource, Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, - Target, TraitItem, TraitItemKind, TraitRef, TyKind, UnOp, + ExprKind, FnDecl, ForeignItem, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, + MatchSource, Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Target, + TraitItem, TraitItemKind, TraitRef, TyKind, UnOp, }; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::place::PlaceBase; @@ -360,24 +360,14 @@ pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> { } } -pub fn get_qpath_generics<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx GenericArgs<'tcx>> { - match path { - QPath::Resolved(_, p) => p.segments.last().and_then(|s| s.args), - QPath::TypeRelative(_, s) => s.args, - QPath::LangItem(..) => None, - } -} - -pub fn qpath_generic_tys<'tcx>(path: &QPath<'tcx>) -> impl Iterator> { - get_qpath_generics(path) - .map_or([].as_ref(), |a| a.args) +pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator> { + last_path_segment(qpath) + .args + .map_or(&[][..], |a| a.args) .iter() - .filter_map(|a| { - if let hir::GenericArg::Type(ty) = a { - Some(ty) - } else { - None - } + .filter_map(|a| match a { + hir::GenericArg::Type(ty) => Some(ty), + _ => None, }) } From 66a83d33ea9a39d1fc0f4c2ca058c0ce4884a71a Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Wed, 5 Jan 2022 20:56:29 -0600 Subject: [PATCH 05/10] Factor out some ty param utils --- clippy_lints/src/types/box_collection.rs | 27 ++++++------- clippy_lints/src/types/option_option.rs | 30 +++++++++------ clippy_lints/src/types/rc_buffer.rs | 33 ++++++++++------ clippy_lints/src/types/rc_mutex.rs | 6 ++- .../src/types/redundant_allocation.rs | 19 +++++----- clippy_utils/src/lib.rs | 38 ------------------- 6 files changed, 63 insertions(+), 90 deletions(-) diff --git a/clippy_lints/src/types/box_collection.rs b/clippy_lints/src/types/box_collection.rs index 538c10a5b204..21a9558ec076 100644 --- a/clippy_lints/src/types/box_collection.rs +++ b/clippy_lints/src/types/box_collection.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::is_ty_param_diagnostic_item; +use clippy_utils::{path_def_id, qpath_generic_tys}; use rustc_hir::{self as hir, def_id::DefId, QPath}; use rustc_lint::LateContext; -use rustc_span::symbol::sym; +use rustc_span::{sym, Symbol}; use super::BOX_COLLECTION; @@ -11,10 +11,9 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ if Some(def_id) == cx.tcx.lang_items().owned_box(); if let Some(item_type) = get_std_collection(cx, qpath); then { - let generic = if item_type == "String" { - "" - } else { - "<..>" + let generic = match item_type { + sym::String => "", + _ => "<..>", }; span_lint_and_help( cx, @@ -37,14 +36,10 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ } } -fn get_std_collection(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> { - if is_ty_param_diagnostic_item(cx, qpath, sym::Vec).is_some() { - Some("Vec") - } else if is_ty_param_diagnostic_item(cx, qpath, sym::String).is_some() { - Some("String") - } else if is_ty_param_diagnostic_item(cx, qpath, sym::HashMap).is_some() { - Some("HashMap") - } else { - None - } +fn get_std_collection(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option { + let param = qpath_generic_tys(qpath).next()?; + let id = path_def_id(cx, param)?; + cx.tcx + .get_diagnostic_name(id) + .filter(|&name| matches!(name, sym::HashMap | sym::String | sym::Vec)) } diff --git a/clippy_lints/src/types/option_option.rs b/clippy_lints/src/types/option_option.rs index 903e62995c61..8767e3c30a68 100644 --- a/clippy_lints/src/types/option_option.rs +++ b/clippy_lints/src/types/option_option.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_ty_param_diagnostic_item; +use clippy_utils::{path_def_id, qpath_generic_tys}; +use if_chain::if_chain; use rustc_hir::{self as hir, def_id::DefId, QPath}; use rustc_lint::LateContext; use rustc_span::symbol::sym; @@ -7,16 +8,21 @@ use rustc_span::symbol::sym; use super::OPTION_OPTION; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { - if cx.tcx.is_diagnostic_item(sym::Option, def_id) && is_ty_param_diagnostic_item(cx, qpath, sym::Option).is_some() { - span_lint( - cx, - OPTION_OPTION, - hir_ty.span, - "consider using `Option` instead of `Option>` or a custom \ - enum if you need to distinguish all 3 cases", - ); - true - } else { - false + if_chain! { + if cx.tcx.is_diagnostic_item(sym::Option, def_id); + if let Some(arg) = qpath_generic_tys(qpath).next(); + if path_def_id(cx, arg) == Some(def_id); + then { + span_lint( + cx, + OPTION_OPTION, + hir_ty.span, + "consider using `Option` instead of `Option>` or a custom \ + enum if you need to distinguish all 3 cases", + ); + true + } else { + false + } } } diff --git a/clippy_lints/src/types/rc_buffer.rs b/clippy_lints/src/types/rc_buffer.rs index 0a2df7d21883..4d72a29e8c74 100644 --- a/clippy_lints/src/types/rc_buffer.rs +++ b/clippy_lints/src/types/rc_buffer.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_ty_param_diagnostic_item, qpath_generic_tys}; +use clippy_utils::{path_def_id, qpath_generic_tys}; use rustc_errors::Applicability; use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind}; use rustc_lint::LateContext; @@ -20,7 +20,12 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ format!("Rc<{}>", alternate), Applicability::MachineApplicable, ); - } else if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::Vec) { + } else { + let Some(ty) = qpath_generic_tys(qpath).next() else { return false }; + let Some(id) = path_def_id(cx, ty) else { return false }; + if !cx.tcx.is_diagnostic_item(sym::Vec, id) { + return false; + } let qpath = match &ty.kind { TyKind::Path(qpath) => qpath, _ => return false, @@ -55,7 +60,11 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ format!("Arc<{}>", alternate), Applicability::MachineApplicable, ); - } else if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::Vec) { + } else if let Some(ty) = qpath_generic_tys(qpath).next() { + let Some(id) = path_def_id(cx, ty) else { return false }; + if !cx.tcx.is_diagnostic_item(sym::Vec, id) { + return false; + } let qpath = match &ty.kind { TyKind::Path(qpath) => qpath, _ => return false, @@ -85,13 +94,13 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ } fn match_buffer_type(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> { - if is_ty_param_diagnostic_item(cx, qpath, sym::String).is_some() { - Some("str") - } else if is_ty_param_diagnostic_item(cx, qpath, sym::OsString).is_some() { - Some("std::ffi::OsStr") - } else if is_ty_param_diagnostic_item(cx, qpath, sym::PathBuf).is_some() { - Some("std::path::Path") - } else { - None - } + let ty = qpath_generic_tys(qpath).next()?; + let id = path_def_id(cx, ty)?; + let path = match cx.tcx.get_diagnostic_name(id)? { + sym::String => "str", + sym::OsString => "std::ffi::OsStr", + sym::PathBuf => "std::path::Path", + _ => return None, + }; + Some(path) } diff --git a/clippy_lints/src/types/rc_mutex.rs b/clippy_lints/src/types/rc_mutex.rs index d54608a07bb2..a75972cf3ddb 100644 --- a/clippy_lints/src/types/rc_mutex.rs +++ b/clippy_lints/src/types/rc_mutex.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::is_ty_param_diagnostic_item; +use clippy_utils::{path_def_id, qpath_generic_tys}; use if_chain::if_chain; use rustc_hir::{self as hir, def_id::DefId, QPath}; use rustc_lint::LateContext; @@ -10,7 +10,9 @@ use super::RC_MUTEX; pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool { if_chain! { if cx.tcx.is_diagnostic_item(sym::Rc, def_id) ; - if let Some(_) = is_ty_param_diagnostic_item(cx, qpath, sym::Mutex) ; + if let Some(arg) = qpath_generic_tys(qpath).next(); + if let Some(id) = path_def_id(cx, arg); + if cx.tcx.is_diagnostic_item(sym::Mutex, id); then { span_lint_and_help( cx, diff --git a/clippy_lints/src/types/redundant_allocation.rs b/clippy_lints/src/types/redundant_allocation.rs index 8638197a5842..10d2ae2eb1db 100644 --- a/clippy_lints/src/types/redundant_allocation.rs +++ b/clippy_lints/src/types/redundant_allocation.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{snippet, snippet_with_applicability}; -use clippy_utils::{is_ty_param_diagnostic_item, is_ty_param_lang_item, qpath_generic_tys}; +use clippy_utils::{path_def_id, qpath_generic_tys}; use rustc_errors::Applicability; -use rustc_hir::{self as hir, def_id::DefId, LangItem, QPath, TyKind}; +use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; @@ -39,14 +39,13 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_ return true; } - let (inner_sym, ty) = if let Some(ty) = is_ty_param_lang_item(cx, qpath, LangItem::OwnedBox) { - ("Box", ty) - } else if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::Rc) { - ("Rc", ty) - } else if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::Arc) { - ("Arc", ty) - } else { - return false; + let Some(ty) = qpath_generic_tys(qpath).next() else { return false }; + let Some(id) = path_def_id(cx, ty) else { return false }; + let (inner_sym, ty) = match cx.tcx.get_diagnostic_name(id) { + Some(sym::Arc) => ("Arc", ty), + Some(sym::Rc) => ("Rc", ty), + _ if Some(id) == cx.tcx.lang_items().owned_box() => ("Box", ty), + _ => return false, }; let inner_qpath = match &ty.kind { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 82d502386668..ed73364841c5 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -262,44 +262,6 @@ pub fn is_wild(pat: &Pat<'_>) -> bool { matches!(pat.kind, PatKind::Wild) } -/// Checks if the first type parameter is a lang item. -pub fn is_ty_param_lang_item<'tcx>( - cx: &LateContext<'_>, - qpath: &QPath<'tcx>, - item: LangItem, -) -> Option<&'tcx hir::Ty<'tcx>> { - let ty = qpath_generic_tys(qpath).next()?; - - if let TyKind::Path(qpath) = &ty.kind { - cx.qpath_res(qpath, ty.hir_id) - .opt_def_id() - .map_or(false, |id| { - cx.tcx.lang_items().require(item).map_or(false, |lang_id| id == lang_id) - }) - .then(|| ty) - } else { - None - } -} - -/// Checks if the first type parameter is a diagnostic item. -pub fn is_ty_param_diagnostic_item<'tcx>( - cx: &LateContext<'_>, - qpath: &QPath<'tcx>, - item: Symbol, -) -> Option<&'tcx hir::Ty<'tcx>> { - let ty = qpath_generic_tys(qpath).next()?; - - if let TyKind::Path(qpath) = &ty.kind { - cx.qpath_res(qpath, ty.hir_id) - .opt_def_id() - .map_or(false, |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. /// This is a deprecated function, consider using [`is_trait_method`]. pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool { From deadc255883a726abee105564bc9a0f65f01e62b Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 2 Nov 2021 09:43:31 -0500 Subject: [PATCH 06/10] Factor out differing_macro_contexts --- clippy_lints/src/blocks_in_if_conditions.rs | 6 +++--- clippy_lints/src/formatting.rs | 14 ++++++-------- clippy_lints/src/implicit_hasher.rs | 3 +-- clippy_lints/src/methods/option_map_unwrap_or.rs | 3 +-- clippy_lints/src/swap.rs | 4 ++-- clippy_lints/src/unwrap.rs | 7 ++++--- clippy_utils/src/hir_utils.rs | 3 +-- clippy_utils/src/lib.rs | 7 ------- doc/common_tools_writing_lints.md | 8 ++++++-- 9 files changed, 24 insertions(+), 31 deletions(-) diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index c4956bacf436..4c4dd85d518a 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::get_parent_expr; use clippy_utils::higher; use clippy_utils::source::snippet_block_with_applicability; use clippy_utils::ty::implements_trait; -use clippy_utils::{differing_macro_contexts, get_parent_expr}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; @@ -97,7 +97,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions { if let Some(ex) = &block.expr { // don't dig into the expression here, just suggest that they remove // the block - if expr.span.from_expansion() || differing_macro_contexts(expr.span, ex.span) { + if expr.span.from_expansion() || ex.span.from_expansion() { return; } let mut applicability = Applicability::MachineApplicable; @@ -122,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions { } } else { let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span); - if span.from_expansion() || differing_macro_contexts(expr.span, span) { + if span.from_expansion() || expr.span.from_expansion() { return; } // move block higher diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index ae18f8081bcc..57964b8d48ea 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note}; -use clippy_utils::differing_macro_contexts; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; @@ -135,7 +134,7 @@ impl EarlyLintPass for Formatting { /// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint. fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::Assign(ref lhs, ref rhs, _) = expr.kind { - if !differing_macro_contexts(lhs.span, rhs.span) && !lhs.span.from_expansion() { + if !lhs.span.from_expansion() && !rhs.span.from_expansion() { let eq_span = lhs.span.between(rhs.span); if let ExprKind::Unary(op, ref sub_rhs) = rhs.kind { if let Some(eq_snippet) = snippet_opt(cx, eq_span) { @@ -165,7 +164,7 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) { fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) { if_chain! { if let ExprKind::Binary(ref binop, ref lhs, ref rhs) = expr.kind; - if !differing_macro_contexts(lhs.span, rhs.span) && !lhs.span.from_expansion(); + if !lhs.span.from_expansion() && !rhs.span.from_expansion(); // span between BinOp LHS and RHS let binop_span = lhs.span.between(rhs.span); // if RHS is an UnOp @@ -206,8 +205,8 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { if_chain! { if let ExprKind::If(_, then, Some(else_)) = &expr.kind; if is_block(else_) || is_if(else_); - if !differing_macro_contexts(then.span, else_.span); - if !then.span.from_expansion() && !in_external_macro(cx.sess(), expr.span); + if !then.span.from_expansion() && !else_.span.from_expansion(); + if !in_external_macro(cx.sess(), expr.span); // workaround for rust-lang/rust#43081 if expr.span.lo().0 != 0 && expr.span.hi().0 != 0; @@ -268,7 +267,7 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) { for element in array { if_chain! { if let ExprKind::Binary(ref op, ref lhs, _) = element.kind; - if has_unary_equivalent(op.node) && !differing_macro_contexts(lhs.span, op.span); + if has_unary_equivalent(op.node) && lhs.span.ctxt() == op.span.ctxt(); let space_span = lhs.span.between(op.span); if let Some(space_snippet) = snippet_opt(cx, space_span); let lint_span = lhs.span.with_lo(lhs.span.hi()); @@ -291,8 +290,7 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) { fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) { if_chain! { - if !differing_macro_contexts(first.span, second.span); - if !first.span.from_expansion(); + if !first.span.from_expansion() && !second.span.from_expansion(); if let ExprKind::If(cond_expr, ..) = &first.kind; if is_block(second) || is_if(second); diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index eed25e9bc0ea..3fb7e5dfd6cd 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -17,7 +17,6 @@ use rustc_typeck::hir_ty_to_ty; use if_chain::if_chain; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; -use clippy_utils::differing_macro_contexts; use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; @@ -123,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { vis.visit_ty(impl_.self_ty); for target in &vis.found { - if differing_macro_contexts(item.span, target.span()) { + if item.span.ctxt() != target.span().ctxt() { return; } diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 9c6f42110318..6c641af59f92 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::differing_macro_contexts; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_copy; use clippy_utils::ty::is_type_diagnostic_item; @@ -48,7 +47,7 @@ pub(super) fn check<'tcx>( } } - if differing_macro_contexts(unwrap_arg.span, map_span) { + if unwrap_arg.span.ctxt() != map_span.ctxt() { return; } diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 4c10b12437d7..1885f3ca414d 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{can_mut_borrow_both, differing_macro_contexts, eq_expr_value, std_or_core}; +use clippy_utils::{can_mut_borrow_both, eq_expr_value, std_or_core}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind}; @@ -172,7 +172,7 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) { if_chain! { if let StmtKind::Semi(first) = w[0].kind; if let StmtKind::Semi(second) = w[1].kind; - if !differing_macro_contexts(first.span, second.span); + if first.span.ctxt() == second.span.ctxt(); if let ExprKind::Assign(lhs0, rhs0, _) = first.kind; if let ExprKind::Assign(lhs1, rhs1, _) = second.kind; if eq_expr_value(cx, lhs0, rhs1); diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index e98404870134..9b9e25326f96 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{differing_macro_contexts, path_to_local, usage::is_potentially_mutated}; +use clippy_utils::{path_to_local, usage::is_potentially_mutated}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor}; @@ -238,8 +238,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { if let Some(unwrappable) = self.unwrappables.iter() .find(|u| u.local_id == id); // Span contexts should not differ with the conditional branch - if !differing_macro_contexts(unwrappable.branch.span, expr.span); - if !differing_macro_contexts(unwrappable.branch.span, unwrappable.check.span); + let span_ctxt = expr.span.ctxt(); + if unwrappable.branch.span.ctxt() == span_ctxt; + if unwrappable.check.span.ctxt() == span_ctxt; then { if call_to_unwrap == unwrappable.safe_to_unwrap { let is_entire_condition = unwrappable.is_entire_condition; diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index ed573ad90561..a2b10c12eb90 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1,5 +1,4 @@ use crate::consts::{constant_context, constant_simple}; -use crate::differing_macro_contexts; use crate::source::snippet_opt; use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxHasher; @@ -186,7 +185,7 @@ impl HirEqInterExpr<'_, '_, '_> { #[allow(clippy::similar_names)] pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool { - if !self.inner.allow_side_effects && differing_macro_contexts(left.span, right.span) { + if !self.inner.allow_side_effects && left.span.ctxt() != right.span.ctxt() { return false; } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index ed73364841c5..f10f130bc32b 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -134,13 +134,6 @@ macro_rules! extract_msrv_attr { }; } -/// Returns `true` if the two spans come from differing expansions (i.e., one is -/// from a macro and one isn't). -#[must_use] -pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool { - rhs.ctxt() != lhs.ctxt() -} - /// If the given expression is a local binding, find the initializer expression. /// If that initializer expression is another local binding, find its initializer again. /// This process repeats as long as possible (but usually no more than once). Initializer diff --git a/doc/common_tools_writing_lints.md b/doc/common_tools_writing_lints.md index 6c8a3dc418b1..36c454745ba0 100644 --- a/doc/common_tools_writing_lints.md +++ b/doc/common_tools_writing_lints.md @@ -235,7 +235,11 @@ Use the following functions to deal with macros: assert_eq!(in_external_macro(cx.sess(), match_span), true); ``` -- `differing_macro_contexts()`: returns true if the two given spans are not from the same context +- `span.ctxt()`: the span's context represents whether it is from expansion, and if so, what expanded it + +One thing `SpanContext` is useful for is to check if two spans are in the same context. For example, +in `a == b`, `a` and `b` have the same context. In a `macro_rules!` with `a == $b`, `$b` is expanded to some +expression with a different context from `a`. ```rust macro_rules! m { @@ -252,7 +256,7 @@ Use the following functions to deal with macros: // These spans are not from the same context // x.is_some() is from inside the macro // x.unwrap() is from outside the macro - assert_eq!(differing_macro_contexts(x_is_some_span, x_unwrap_span), true); + assert_eq!(x_is_some_span.ctxt(), x_unwrap_span.ctxt()); ``` [TyS]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyS.html From 98c6381a387ac05e27c03ccfc64146bf4934f5c8 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 6 Jan 2022 09:31:38 -0600 Subject: [PATCH 07/10] Factor out single_segment_path --- clippy_lints/src/loops/single_element_loop.rs | 24 +++++++---------- clippy_lints/src/methods/chars_cmp.rs | 15 +++++------ .../src/methods/option_map_or_none.rs | 13 +++++----- clippy_lints/src/ranges.rs | 26 +++++-------------- clippy_utils/src/lib.rs | 8 ------ 5 files changed, 29 insertions(+), 57 deletions(-) diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs index 15f419e4410c..36ecd83f7d64 100644 --- a/clippy_lints/src/loops/single_element_loop.rs +++ b/clippy_lints/src/loops/single_element_loop.rs @@ -1,10 +1,9 @@ use super::SINGLE_ELEMENT_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::single_segment_path; -use clippy_utils::source::{indent_of, snippet}; +use clippy_utils::source::{indent_of, snippet_with_applicability}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{BorrowKind, Expr, ExprKind, Pat, PatKind}; +use rustc_hir::{BorrowKind, Expr, ExprKind, Pat}; use rustc_lint::LateContext; pub(super) fn check<'tcx>( @@ -16,24 +15,21 @@ pub(super) fn check<'tcx>( ) { let arg_expr = match arg.kind { ExprKind::AddrOf(BorrowKind::Ref, _, ref_arg) => ref_arg, - ExprKind::MethodCall(method, args, _) if args.len() == 1 && method.ident.name == rustc_span::sym::iter => { - &args[0] - }, + ExprKind::MethodCall(method, [arg], _) if method.ident.name == rustc_span::sym::iter => arg, _ => return, }; if_chain! { - if let PatKind::Binding(.., target, _) = pat.kind; if let ExprKind::Array([arg_expression]) = arg_expr.kind; - if let ExprKind::Path(ref list_item) = arg_expression.kind; - if let Some(list_item_name) = single_segment_path(list_item).map(|ps| ps.ident.name); if let ExprKind::Block(block, _) = body.kind; if !block.stmts.is_empty(); - then { - let mut block_str = snippet(cx, block.span, "..").into_owned(); + let mut applicability = Applicability::MachineApplicable; + let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability); + let arg_snip = snippet_with_applicability(cx, arg_expression.span, "..", &mut applicability); + let mut block_str = snippet_with_applicability(cx, block.span, "..", &mut applicability).into_owned(); block_str.remove(0); block_str.pop(); - + let indent = " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0)); span_lint_and_sugg( cx, @@ -41,8 +37,8 @@ pub(super) fn check<'tcx>( expr.span, "for loop over a single element", "try", - format!("{{\n{}let {} = &{};{}}}", " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0)), target.name, list_item_name, block_str), - Applicability::MachineApplicable + format!("{{\n{}let {} = &{};{}}}", indent, pat_snip, arg_snip, block_str), + applicability, ) } } diff --git a/clippy_lints/src/methods/chars_cmp.rs b/clippy_lints/src/methods/chars_cmp.rs index 514c41187655..2cf2c5641bf1 100644 --- a/clippy_lints/src/methods/chars_cmp.rs +++ b/clippy_lints/src/methods/chars_cmp.rs @@ -1,13 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{method_chain_args, single_segment_path}; +use clippy_utils::{method_chain_args, path_def_id}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_lint::Lint; -use rustc_middle::ty; -use rustc_span::sym; +use rustc_middle::ty::{self, DefIdTree}; /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints. pub(super) fn check( @@ -19,11 +18,9 @@ pub(super) fn check( ) -> bool { if_chain! { if let Some(args) = method_chain_args(info.chain, chain_methods); - if let hir::ExprKind::Call(fun, arg_char) = info.other.kind; - if arg_char.len() == 1; - if let hir::ExprKind::Path(ref qpath) = fun.kind; - if let Some(segment) = single_segment_path(qpath); - if segment.ident.name == sym::Some; + if let hir::ExprKind::Call(fun, [arg_char]) = info.other.kind; + if let Some(id) = path_def_id(cx, fun).and_then(|ctor_id| cx.tcx.parent(ctor_id)); + if Some(id) == cx.tcx.lang_items().option_some_variant(); then { let mut applicability = Applicability::MachineApplicable; let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs(); @@ -42,7 +39,7 @@ pub(super) fn check( if info.eq { "" } else { "!" }, snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability), suggest, - snippet_with_applicability(cx, arg_char[0].span, "..", &mut applicability)), + snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)), applicability, ); diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs index 5e5c1038e829..bdf8cea12073 100644 --- a/clippy_lints/src/methods/option_map_or_none.rs +++ b/clippy_lints/src/methods/option_map_or_none.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_lang_ctor, single_segment_path}; +use clippy_utils::{is_lang_ctor, path_def_id}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_lint::LateContext; +use rustc_middle::ty::DefIdTree; use rustc_span::symbol::sym; use super::OPTION_MAP_OR_NONE; @@ -76,13 +77,11 @@ pub(super) fn check<'tcx>( if let hir::ExprKind::Closure(_, _, id, span, _) = map_arg.kind; let arg_snippet = snippet(cx, span, ".."); let body = cx.tcx.hir().body(id); - if let Some((func, arg_char)) = reduce_unit_expression(cx, &body.value); - if arg_char.len() == 1; - if let hir::ExprKind::Path(ref qpath) = func.kind; - if let Some(segment) = single_segment_path(qpath); - if segment.ident.name == sym::Some; + if let Some((func, [arg_char])) = reduce_unit_expression(cx, &body.value); + if let Some(id) = path_def_id(cx, func).and_then(|ctor_id| cx.tcx.parent(ctor_id)); + if Some(id) == cx.tcx.lang_items().option_some_variant(); then { - let func_snippet = snippet(cx, arg_char[0].span, ".."); + let func_snippet = snippet(cx, arg_char.span, ".."); let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ `map(..)` instead"; return span_lint_and_sugg( diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 8065ed3ffc55..e213c208794c 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -2,19 +2,18 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; -use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, single_segment_path}; +use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, path_to_local}; use clippy_utils::{higher, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, QPath}; +use rustc_hir::{BinOpKind, Expr, ExprKind, HirId, PathSegment, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; use rustc_span::sym; -use rustc_span::symbol::Ident; use std::cmp::Ordering; declare_clippy_lint! { @@ -220,12 +219,12 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<' _ => return, }; // value, name, order (higher/lower), inclusiveness - if let (Some((lval, lname, name_span, lval_span, lord, linc)), Some((rval, rname, _, rval_span, rord, rinc))) = + if let (Some((lval, lid, name_span, lval_span, lord, linc)), Some((rval, rid, _, rval_span, rord, rinc))) = (check_range_bounds(cx, l), check_range_bounds(cx, r)) { // we only lint comparisons on the same name and with different // direction - if lname != rname || lord == rord { + if lid != rid || lord == rord { return; } let ord = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(l), &lval, &rval); @@ -293,7 +292,7 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<' } } -fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant, Ident, Span, Span, Ordering, bool)> { +fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant, HirId, Span, Span, Ordering, bool)> { if let ExprKind::Binary(ref op, l, r) = ex.kind { let (inclusive, ordering) = match op.node { BinOpKind::Gt => (false, Ordering::Greater), @@ -302,11 +301,11 @@ fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant, BinOpKind::Le => (true, Ordering::Less), _ => return None, }; - if let Some(id) = match_ident(l) { + if let Some(id) = path_to_local(l) { if let Some((c, _)) = constant(cx, cx.typeck_results(), r) { return Some((c, id, l.span, r.span, ordering, inclusive)); } - } else if let Some(id) = match_ident(r) { + } else if let Some(id) = path_to_local(r) { if let Some((c, _)) = constant(cx, cx.typeck_results(), l) { return Some((c, id, r.span, l.span, ordering.reverse(), inclusive)); } @@ -315,17 +314,6 @@ fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant, None } -fn match_ident(e: &Expr<'_>) -> Option { - if let ExprKind::Path(ref qpath) = e.kind { - if let Some(seg) = single_segment_path(qpath) { - if seg.args.is_none() { - return Some(seg.ident); - } - } - } - None -} - fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args: &[Expr<'_>], span: Span) { if_chain! { if path.ident.as_str() == "zip"; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index f10f130bc32b..3df7af601cf7 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -326,14 +326,6 @@ pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator(path: &QPath<'tcx>) -> Option<&'tcx PathSegment<'tcx>> { - match *path { - QPath::Resolved(_, path) => path.segments.get(0), - QPath::TypeRelative(_, seg) => Some(seg), - QPath::LangItem(..) => None, - } -} - /// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the /// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from /// `QPath::Resolved.1.res.opt_def_id()`. From 3771fe4adeafc0825a562b5b542ce1be0350b7dd Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 6 Jan 2022 09:35:25 -0600 Subject: [PATCH 08/10] Factor out expr_path_res --- clippy_lints/src/misc.rs | 7 +++---- clippy_lints/src/ptr.rs | 7 ++++--- clippy_utils/src/lib.rs | 17 ++--------------- clippy_utils/src/ty.rs | 4 ++-- 4 files changed, 11 insertions(+), 24 deletions(-) diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 3918bdbdf438..ac82dd306a52 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -20,8 +20,8 @@ use rustc_span::symbol::sym; use clippy_utils::consts::{constant, Constant}; use clippy_utils::sugg::Sugg; use clippy_utils::{ - expr_path_res, get_item_name, get_parent_expr, in_constant, is_diag_trait_item, is_integer_const, iter_input_pats, - last_path_segment, match_any_def_paths, paths, unsext, SpanlessEq, + get_item_name, get_parent_expr, in_constant, is_diag_trait_item, is_integer_const, iter_input_pats, + last_path_segment, match_any_def_paths, path_def_id, paths, unsext, SpanlessEq, }; declare_clippy_lint! { @@ -583,8 +583,7 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: ) }, ExprKind::Call(path, [arg]) => { - if expr_path_res(cx, path) - .opt_def_id() + if path_def_id(cx, path) .and_then(|id| match_any_def_paths(cx, id, &[&paths::FROM_STR_METHOD, &paths::FROM_FROM])) .is_some() { diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index b5d65542de0b..26717c0c0fdf 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -4,7 +4,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the use clippy_utils::source::snippet_opt; use clippy_utils::ty::expr_sig; use clippy_utils::{ - expr_path_res, get_expr_use_or_unification_node, is_lint_allowed, match_any_diagnostic_items, path_to_local, paths, + expr_path_res, get_expr_use_or_unification_node, is_lint_allowed, is_lint_allowed, match_any_diagnostic_items, + path_def_id, path_to_local, paths, paths, }; use if_chain::if_chain; use rustc_errors::Applicability; @@ -665,8 +666,8 @@ fn get_rptr_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutabil fn is_null_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { if let ExprKind::Call(pathexp, []) = expr.kind { - expr_path_res(cx, pathexp).opt_def_id().map_or(false, |id| { - match_any_diagnostic_items(cx, id, &[sym::ptr_null, sym::ptr_null_mut]).is_some() + path_def_id(cx, pathexp).map_or(false, |id| { + matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ptr_null | sym::ptr_null_mut)) }) } else { false diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 3df7af601cf7..eeadc6d4ddaa 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -357,15 +357,6 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool { } } -/// If the expression is a path, resolve it. Otherwise, return `Res::Err`. -pub fn expr_path_res(cx: &LateContext<'_>, expr: &Expr<'_>) -> Res { - if let ExprKind::Path(p) = &expr.kind { - cx.qpath_res(p, expr.hir_id) - } else { - Res::Err - } -} - /// Resolves the path to a `DefId` and checks if it matches the given path. pub fn is_qpath_def_path(cx: &LateContext<'_>, path: &QPath<'_>, hir_id: HirId, segments: &[&str]) -> bool { cx.qpath_res(path, hir_id) @@ -377,17 +368,13 @@ pub fn is_qpath_def_path(cx: &LateContext<'_>, path: &QPath<'_>, hir_id: HirId, /// /// Please use `is_expr_diagnostic_item` if the target is a diagnostic item. pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool { - expr_path_res(cx, expr) - .opt_def_id() - .map_or(false, |id| match_def_path(cx, id, segments)) + path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, segments)) } /// If the expression is a path, resolves it to a `DefId` and checks if it matches the given /// diagnostic item. pub fn is_expr_diagnostic_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool { - expr_path_res(cx, expr) - .opt_def_id() - .map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id)) + path_def_id(cx, expr).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id)) } /// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index d057da73302a..aa3ea2d23da7 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -20,7 +20,7 @@ use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::query::normalize::AtExt; use std::iter; -use crate::{expr_path_res, match_def_path, must_use_attr}; +use crate::{match_def_path, must_use_attr, path_res}; // Checks if the given type implements copy. pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { @@ -443,7 +443,7 @@ impl<'tcx> ExprFnSig<'tcx> { /// If the expression is function like, get the signature for it. pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option> { - if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = expr_path_res(cx, expr) { + if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = path_res(cx, expr) { Some(ExprFnSig::Sig(cx.tcx.fn_sig(id))) } else { let ty = cx.typeck_results().expr_ty_adjusted(expr).peel_refs(); From ece7fa4f9c4e934a3176de9abcf9ab3b71a6dd7c Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 6 Jan 2022 09:39:46 -0600 Subject: [PATCH 09/10] Factor out match_any_diagnostic_items --- clippy_lints/src/ptr.rs | 5 +--- .../transmute/unsound_collection_transmute.rs | 30 ++++++++++--------- clippy_utils/src/lib.rs | 10 +------ 3 files changed, 18 insertions(+), 27 deletions(-) diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 26717c0c0fdf..6decd18b0a3e 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -3,10 +3,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::expr_sig; -use clippy_utils::{ - expr_path_res, get_expr_use_or_unification_node, is_lint_allowed, is_lint_allowed, match_any_diagnostic_items, - path_def_id, path_to_local, paths, paths, -}; +use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; diff --git a/clippy_lints/src/transmute/unsound_collection_transmute.rs b/clippy_lints/src/transmute/unsound_collection_transmute.rs index 2ce8d4031d77..2d67401a15f2 100644 --- a/clippy_lints/src/transmute/unsound_collection_transmute.rs +++ b/clippy_lints/src/transmute/unsound_collection_transmute.rs @@ -1,29 +1,31 @@ use super::utils::is_layout_incompatible; use super::UNSOUND_COLLECTION_TRANSMUTE; use clippy_utils::diagnostics::span_lint; -use clippy_utils::match_any_diagnostic_items; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_span::symbol::{sym, Symbol}; - -// used to check for UNSOUND_COLLECTION_TRANSMUTE -static COLLECTIONS: &[Symbol] = &[ - sym::Vec, - sym::VecDeque, - sym::BinaryHeap, - sym::BTreeSet, - sym::BTreeMap, - sym::HashSet, - sym::HashMap, -]; +use rustc_span::symbol::sym; /// Checks for `unsound_collection_transmute` lint. /// Returns `true` if it's triggered, otherwise returns `false`. pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> bool { match (&from_ty.kind(), &to_ty.kind()) { (ty::Adt(from_adt, from_substs), ty::Adt(to_adt, to_substs)) => { - if from_adt.did != to_adt.did || match_any_diagnostic_items(cx, to_adt.did, COLLECTIONS).is_none() { + if from_adt.did != to_adt.did { + return false; + } + if !matches!( + cx.tcx.get_diagnostic_name(to_adt.did), + Some( + sym::BTreeMap + | sym::BTreeSet + | sym::BinaryHeap + | sym::HashMap + | sym::HashSet + | sym::Vec + | sym::VecDeque + ) + ) { return false; } if from_substs diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index eeadc6d4ddaa..62066987232a 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1615,7 +1615,7 @@ pub fn match_function_call<'tcx>( /// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if /// any. /// -/// Please use `match_any_diagnostic_items` if the targets are all diagnostic items. +/// Please use `tcx.get_diagnostic_name` if the targets are all diagnostic items. pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]]) -> Option { let search_path = cx.get_def_path(did); paths @@ -1623,14 +1623,6 @@ pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]]) .position(|p| p.iter().map(|x| Symbol::intern(x)).eq(search_path.iter().copied())) } -/// Checks if the given `DefId` matches any of provided diagnostic items. Returns the index of -/// matching path, if any. -pub fn match_any_diagnostic_items(cx: &LateContext<'_>, def_id: DefId, diag_items: &[Symbol]) -> Option { - diag_items - .iter() - .position(|item| cx.tcx.is_diagnostic_item(*item, def_id)) -} - /// Checks if the given `DefId` matches the path. pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) -> bool { // We should probably move to Symbols in Clippy as well rather than interning every time. From bd583d91a1bf3717f724a38531e142aa4a9ee6cc Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 6 Jan 2022 12:41:17 -0600 Subject: [PATCH 10/10] Factor out is_qpath_def_path --- clippy_lints/src/infinite_iter.rs | 12 ++-- clippy_lints/src/matches.rs | 62 +++++++++++-------- .../methods/manual_saturating_arithmetic.rs | 8 +-- clippy_utils/src/lib.rs | 10 +-- 4 files changed, 44 insertions(+), 48 deletions(-) diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 3008e86ef8b2..b6badef02f58 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use clippy_utils::{get_trait_def_id, higher, is_qpath_def_path, paths}; +use clippy_utils::{get_trait_def_id, higher, match_def_path, path_def_id, paths}; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -167,13 +167,9 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { }, ExprKind::Block(block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)), ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e), - ExprKind::Call(path, _) => { - if let ExprKind::Path(ref qpath) = path.kind { - is_qpath_def_path(cx, qpath, path.hir_id, &paths::ITER_REPEAT).into() - } else { - Finite - } - }, + ExprKind::Call(path, _) => path_def_id(cx, path) + .map_or(false, |id| match_def_path(cx, id, &paths::ITER_REPEAT)) + .into(), ExprKind::Struct(..) => higher::Range::hir(expr).map_or(false, |r| r.end.is_none()).into(), _ => Finite, } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 2579404fb18c..81ae4dacdf61 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -1765,22 +1765,22 @@ where mod redundant_pattern_match { use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::span_lint_and_then; - use clippy_utils::higher; use clippy_utils::source::snippet; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, is_type_lang_item, match_type}; - use clippy_utils::{is_lang_ctor, is_qpath_def_path, is_trait_method, paths}; + use clippy_utils::{higher, match_def_path}; + use clippy_utils::{is_lang_ctor, is_trait_method, paths}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; - use rustc_hir::LangItem::{OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk}; + use rustc_hir::LangItem::{OptionNone, PollPending}; use rustc_hir::{ intravisit::{walk_expr, Visitor}, Arm, Block, Expr, ExprKind, LangItem, MatchSource, Node, Pat, PatKind, QPath, UnOp, }; use rustc_lint::LateContext; - use rustc_middle::ty::{self, subst::GenericArgKind, Ty}; + use rustc_middle::ty::{self, subst::GenericArgKind, DefIdTree, Ty}; use rustc_span::sym; pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { @@ -1956,28 +1956,31 @@ mod redundant_pattern_match { has_else: bool, ) { // also look inside refs - let mut kind = &let_pat.kind; // if we have &None for example, peel it so we can detect "if let None = x" - if let PatKind::Ref(inner, _mutability) = kind { - kind = &inner.kind; - } + let check_pat = match let_pat.kind { + PatKind::Ref(inner, _mutability) => inner, + _ => let_pat, + }; let op_ty = cx.typeck_results().expr_ty(let_expr); // Determine which function should be used, and the type contained by the corresponding // variant. - let (good_method, inner_ty) = match kind { - PatKind::TupleStruct(ref path, [sub_pat], _) => { + let (good_method, inner_ty) = match check_pat.kind { + PatKind::TupleStruct(ref qpath, [sub_pat], _) => { if let PatKind::Wild = sub_pat.kind { - if is_lang_ctor(cx, path, ResultOk) { + let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id); + let Some(id) = res.opt_def_id().and_then(|ctor_id| cx.tcx.parent(ctor_id)) else { return }; + let lang_items = cx.tcx.lang_items(); + if Some(id) == lang_items.result_ok_variant() { ("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty)) - } else if is_lang_ctor(cx, path, ResultErr) { + } else if Some(id) == lang_items.result_err_variant() { ("is_err()", try_get_generic_ty(op_ty, 1).unwrap_or(op_ty)) - } else if is_lang_ctor(cx, path, OptionSome) { + } else if Some(id) == lang_items.option_some_variant() { ("is_some()", op_ty) - } else if is_lang_ctor(cx, path, PollReady) { + } else if Some(id) == lang_items.poll_ready_variant() { ("is_ready()", op_ty) - } else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V4) { + } else if match_def_path(cx, id, &paths::IPADDR_V4) { ("is_ipv4()", op_ty) - } else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V6) { + } else if match_def_path(cx, id, &paths::IPADDR_V6) { ("is_ipv6()", op_ty) } else { return; @@ -2177,17 +2180,22 @@ mod redundant_pattern_match { should_be_left: &'a str, should_be_right: &'a str, ) -> Option<&'a str> { - let body_node_pair = if is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_left) - && is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_right) - { - (&(*arms[0].body).kind, &(*arms[1].body).kind) - } else if is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_left) - && is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_right) - { - (&(*arms[1].body).kind, &(*arms[0].body).kind) - } else { - return None; - }; + let left_id = cx + .typeck_results() + .qpath_res(path_left, arms[0].pat.hir_id) + .opt_def_id()?; + let right_id = cx + .typeck_results() + .qpath_res(path_right, arms[1].pat.hir_id) + .opt_def_id()?; + let body_node_pair = + if match_def_path(cx, left_id, expected_left) && match_def_path(cx, right_id, expected_right) { + (&(*arms[0].body).kind, &(*arms[1].body).kind) + } else if match_def_path(cx, right_id, expected_left) && match_def_path(cx, right_id, expected_right) { + (&(*arms[1].body).kind, &(*arms[0].body).kind) + } else { + return None; + }; match body_node_pair { (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) { diff --git a/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/clippy_lints/src/methods/manual_saturating_arithmetic.rs index 4307cbf00507..0fe510beaa07 100644 --- a/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_qpath_def_path; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{match_def_path, path_def_id}; use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; @@ -93,12 +93,12 @@ fn is_min_or_max<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) -> Option, segments: &[&str]) -> bool { } } -/// Resolves the path to a `DefId` and checks if it matches the given path. -pub fn is_qpath_def_path(cx: &LateContext<'_>, path: &QPath<'_>, hir_id: HirId, segments: &[&str]) -> bool { - cx.qpath_res(path, hir_id) - .opt_def_id() - .map_or(false, |id| match_def_path(cx, id, segments)) -} - /// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path. /// /// Please use `is_expr_diagnostic_item` if the target is a diagnostic item. @@ -1775,8 +1768,7 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool match expr.kind { ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)), - ExprKind::Path(ref path) => is_qpath_def_path(cx, path, expr.hir_id, &paths::CONVERT_IDENTITY), - _ => false, + _ => path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, &paths::CONVERT_IDENTITY)), } }