From 46340f20497fd9f30e08d5c30413f6f45164da89 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 30 Mar 2022 11:57:53 +0200 Subject: [PATCH] clippy: nameres for primitive type impls --- src/tools/clippy/clippy_utils/src/lib.rs | 95 ++++++++++++------- .../conf_disallowed_methods.rs | 4 +- .../conf_disallowed_methods.stderr | 14 ++- 3 files changed, 75 insertions(+), 38 deletions(-) diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index b55075943b2..62e14439801 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -87,6 +87,8 @@ use rustc_middle::hir::place::PlaceBase; use rustc_middle::ty as rustc_ty; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::binding::BindingMode; +use rustc_middle::ty::{IntTy, UintTy, FloatTy}; +use rustc_middle::ty::fast_reject::SimplifiedTypeGen::*; use rustc_middle::ty::{layout::IntegerExt, BorrowKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeFoldable, UpvarCapture}; use rustc_semver::RustcVersion; use rustc_session::Session; @@ -455,14 +457,6 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx> /// 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 { - Some(e) => e, - None => return Res::Err, - } - }; - } fn item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: &str) -> Option { match tcx.def_kind(def_id) { DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx @@ -479,10 +473,36 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res { _ => None, } } - fn find_primitive(_tcx: TyCtxt<'_>, _name: &str) -> Option { - // FIXME: Deal with this without relying on lang items or by only - // looking at a single impl. - None + fn find_primitive<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator + 'tcx { + let single = |ty| tcx.incoherent_impls(ty).iter().copied(); + let empty = || [].iter().copied(); + match name { + "bool" => single(BoolSimplifiedType), + "char" => single(CharSimplifiedType), + "str" => single(StrSimplifiedType), + "array" => single(ArraySimplifiedType), + "slice" => single(SliceSimplifiedType), + // FIXME: rustdoc documents these two using just `pointer`. + // + // Maybe this is something we should do here too. + "const_ptr" => single(PtrSimplifiedType(Mutability::Not)), + "mut_ptr" => single(PtrSimplifiedType(Mutability::Mut)), + "isize" => single(IntSimplifiedType(IntTy::Isize)), + "i8" => single(IntSimplifiedType(IntTy::I8)), + "i16" => single(IntSimplifiedType(IntTy::I16)), + "i32" => single(IntSimplifiedType(IntTy::I32)), + "i64" => single(IntSimplifiedType(IntTy::I64)), + "i128" => single(IntSimplifiedType(IntTy::I128)), + "usize" => single(UintSimplifiedType(UintTy::Usize)), + "u8" => single(UintSimplifiedType(UintTy::U8)), + "u16" => single(UintSimplifiedType(UintTy::U16)), + "u32" => single(UintSimplifiedType(UintTy::U32)), + "u64" => single(UintSimplifiedType(UintTy::U64)), + "u128" => single(UintSimplifiedType(UintTy::U128)), + "f32" => single(FloatSimplifiedType(FloatTy::F32)), + "f64" => single(FloatSimplifiedType(FloatTy::F64)), + _ => empty(), + } } fn find_crate(tcx: TyCtxt<'_>, name: &str) -> Option { tcx.crates(()) @@ -500,30 +520,35 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res { _ => return Res::Err, }; let tcx = cx.tcx; - let first = try_res!( - find_primitive(tcx, base) - .or_else(|| find_crate(tcx, base)) - .and_then(|id| item_child_by_name(tcx, id, first)) - ); + let starts = find_primitive(tcx, base) + .chain(find_crate(tcx, base)) + .flat_map(|id| item_child_by_name(tcx, id, first)); - let last = path - .iter() - .copied() - // for each segment, find the child item - .try_fold(first, |res, segment| { - let def_id = res.def_id(); - if let Some(item) = item_child_by_name(tcx, def_id, segment) { - Some(item) - } else if matches!(res, Res::Def(DefKind::Enum | DefKind::Struct, _)) { - // it is not a child item so check inherent impl items - tcx.inherent_impls(def_id) - .iter() - .find_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, segment)) - } else { - None - } - }); - try_res!(last).expect_non_local() + for first in starts { + let last = path + .iter() + .copied() + // for each segment, find the child item + .try_fold(first, |res, segment| { + let def_id = res.def_id(); + if let Some(item) = item_child_by_name(tcx, def_id, segment) { + Some(item) + } else if matches!(res, Res::Def(DefKind::Enum | DefKind::Struct, _)) { + // it is not a child item so check inherent impl items + tcx.inherent_impls(def_id) + .iter() + .find_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, segment)) + } else { + None + } + }); + + if let Some(last) = last { + return last; + } + } + + Res::Err } /// Convenience function to get the `DefId` of a trait by path. diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs index f8086bd2e4d..338b3b5b28f 100644 --- a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs +++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs @@ -10,8 +10,8 @@ fn main() { let mut a = vec![1, 2, 3, 4]; a.iter().sum::(); - a.sort_unstable(); // FIXME: Warn here + a.sort_unstable(); - let _ = 2.0f32.clamp(3.0f32, 4.0f32); // FIXME: Warn here + let _ = 2.0f32.clamp(3.0f32, 4.0f32); let _ = 2.0f64.clamp(3.0f64, 4.0f64); } diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr index 999ead10d51..5533676aea2 100644 --- a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr @@ -20,5 +20,17 @@ error: use of a disallowed method `std::iter::Iterator::sum` LL | a.iter().sum::(); | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: use of a disallowed method `slice::sort_unstable` + --> $DIR/conf_disallowed_methods.rs:13:5 + | +LL | a.sort_unstable(); + | ^^^^^^^^^^^^^^^^^ + +error: use of a disallowed method `f32::clamp` + --> $DIR/conf_disallowed_methods.rs:15:13 + | +LL | let _ = 2.0f32.clamp(3.0f32, 4.0f32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors