Skip to content

Commit 46340f2

Browse files
committed
clippy: nameres for primitive type impls
1 parent 01d4e83 commit 46340f2

File tree

3 files changed

+75
-38
lines changed

3 files changed

+75
-38
lines changed

src/tools/clippy/clippy_utils/src/lib.rs

+60-35
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ use rustc_middle::hir::place::PlaceBase;
8787
use rustc_middle::ty as rustc_ty;
8888
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
8989
use rustc_middle::ty::binding::BindingMode;
90+
use rustc_middle::ty::{IntTy, UintTy, FloatTy};
91+
use rustc_middle::ty::fast_reject::SimplifiedTypeGen::*;
9092
use rustc_middle::ty::{layout::IntegerExt, BorrowKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeFoldable, UpvarCapture};
9193
use rustc_semver::RustcVersion;
9294
use rustc_session::Session;
@@ -455,14 +457,6 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>
455457
/// Resolves a def path like `std::vec::Vec`.
456458
/// This function is expensive and should be used sparingly.
457459
pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
458-
macro_rules! try_res {
459-
($e:expr) => {
460-
match $e {
461-
Some(e) => e,
462-
None => return Res::Err,
463-
}
464-
};
465-
}
466460
fn item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: &str) -> Option<Res> {
467461
match tcx.def_kind(def_id) {
468462
DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx
@@ -479,10 +473,36 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
479473
_ => None,
480474
}
481475
}
482-
fn find_primitive(_tcx: TyCtxt<'_>, _name: &str) -> Option<DefId> {
483-
// FIXME: Deal with this without relying on lang items or by only
484-
// looking at a single impl.
485-
None
476+
fn find_primitive<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<Item = DefId> + 'tcx {
477+
let single = |ty| tcx.incoherent_impls(ty).iter().copied();
478+
let empty = || [].iter().copied();
479+
match name {
480+
"bool" => single(BoolSimplifiedType),
481+
"char" => single(CharSimplifiedType),
482+
"str" => single(StrSimplifiedType),
483+
"array" => single(ArraySimplifiedType),
484+
"slice" => single(SliceSimplifiedType),
485+
// FIXME: rustdoc documents these two using just `pointer`.
486+
//
487+
// Maybe this is something we should do here too.
488+
"const_ptr" => single(PtrSimplifiedType(Mutability::Not)),
489+
"mut_ptr" => single(PtrSimplifiedType(Mutability::Mut)),
490+
"isize" => single(IntSimplifiedType(IntTy::Isize)),
491+
"i8" => single(IntSimplifiedType(IntTy::I8)),
492+
"i16" => single(IntSimplifiedType(IntTy::I16)),
493+
"i32" => single(IntSimplifiedType(IntTy::I32)),
494+
"i64" => single(IntSimplifiedType(IntTy::I64)),
495+
"i128" => single(IntSimplifiedType(IntTy::I128)),
496+
"usize" => single(UintSimplifiedType(UintTy::Usize)),
497+
"u8" => single(UintSimplifiedType(UintTy::U8)),
498+
"u16" => single(UintSimplifiedType(UintTy::U16)),
499+
"u32" => single(UintSimplifiedType(UintTy::U32)),
500+
"u64" => single(UintSimplifiedType(UintTy::U64)),
501+
"u128" => single(UintSimplifiedType(UintTy::U128)),
502+
"f32" => single(FloatSimplifiedType(FloatTy::F32)),
503+
"f64" => single(FloatSimplifiedType(FloatTy::F64)),
504+
_ => empty(),
505+
}
486506
}
487507
fn find_crate(tcx: TyCtxt<'_>, name: &str) -> Option<DefId> {
488508
tcx.crates(())
@@ -500,30 +520,35 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
500520
_ => return Res::Err,
501521
};
502522
let tcx = cx.tcx;
503-
let first = try_res!(
504-
find_primitive(tcx, base)
505-
.or_else(|| find_crate(tcx, base))
506-
.and_then(|id| item_child_by_name(tcx, id, first))
507-
);
523+
let starts = find_primitive(tcx, base)
524+
.chain(find_crate(tcx, base))
525+
.flat_map(|id| item_child_by_name(tcx, id, first));
508526

509-
let last = path
510-
.iter()
511-
.copied()
512-
// for each segment, find the child item
513-
.try_fold(first, |res, segment| {
514-
let def_id = res.def_id();
515-
if let Some(item) = item_child_by_name(tcx, def_id, segment) {
516-
Some(item)
517-
} else if matches!(res, Res::Def(DefKind::Enum | DefKind::Struct, _)) {
518-
// it is not a child item so check inherent impl items
519-
tcx.inherent_impls(def_id)
520-
.iter()
521-
.find_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, segment))
522-
} else {
523-
None
524-
}
525-
});
526-
try_res!(last).expect_non_local()
527+
for first in starts {
528+
let last = path
529+
.iter()
530+
.copied()
531+
// for each segment, find the child item
532+
.try_fold(first, |res, segment| {
533+
let def_id = res.def_id();
534+
if let Some(item) = item_child_by_name(tcx, def_id, segment) {
535+
Some(item)
536+
} else if matches!(res, Res::Def(DefKind::Enum | DefKind::Struct, _)) {
537+
// it is not a child item so check inherent impl items
538+
tcx.inherent_impls(def_id)
539+
.iter()
540+
.find_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, segment))
541+
} else {
542+
None
543+
}
544+
});
545+
546+
if let Some(last) = last {
547+
return last;
548+
}
549+
}
550+
551+
Res::Err
527552
}
528553

529554
/// Convenience function to get the `DefId` of a trait by path.

src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ fn main() {
1010
let mut a = vec![1, 2, 3, 4];
1111
a.iter().sum::<i32>();
1212

13-
a.sort_unstable(); // FIXME: Warn here
13+
a.sort_unstable();
1414

15-
let _ = 2.0f32.clamp(3.0f32, 4.0f32); // FIXME: Warn here
15+
let _ = 2.0f32.clamp(3.0f32, 4.0f32);
1616
let _ = 2.0f64.clamp(3.0f64, 4.0f64);
1717
}

src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr

+13-1
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,17 @@ error: use of a disallowed method `std::iter::Iterator::sum`
2020
LL | a.iter().sum::<i32>();
2121
| ^^^^^^^^^^^^^^^^^^^^^
2222

23-
error: aborting due to 3 previous errors
23+
error: use of a disallowed method `slice::sort_unstable`
24+
--> $DIR/conf_disallowed_methods.rs:13:5
25+
|
26+
LL | a.sort_unstable();
27+
| ^^^^^^^^^^^^^^^^^
28+
29+
error: use of a disallowed method `f32::clamp`
30+
--> $DIR/conf_disallowed_methods.rs:15:13
31+
|
32+
LL | let _ = 2.0f32.clamp(3.0f32, 4.0f32);
33+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
34+
35+
error: aborting due to 5 previous errors
2436

0 commit comments

Comments
 (0)