Skip to content

Commit 170d486

Browse files
author
Michael Wright
committed
Simplify wrong_self_convention code
Use actual types instead of hir types.
1 parent ebd2498 commit 170d486

File tree

1 file changed

+76
-153
lines changed
  • clippy_lints/src/methods

1 file changed

+76
-153
lines changed

clippy_lints/src/methods/mod.rs

Lines changed: 76 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ use crate::utils::sugg;
2323
use crate::utils::usage::mutated_variables;
2424
use crate::utils::{
2525
get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro, is_copy,
26-
is_ctor_function, is_expn_of, is_self, is_self_ty, iter_input_pats, last_path_segment, match_def_path, match_path,
27-
match_qpath, match_trait_method, match_type, match_var, method_calls, method_chain_args, remove_blocks, return_ty,
28-
same_tys, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint,
29-
span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq,
26+
is_ctor_function, is_expn_of, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_trait_method,
27+
match_type, match_var, method_calls, method_chain_args, remove_blocks, return_ty, same_tys, single_segment_path,
28+
snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_sugg,
29+
span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq,
3030
};
3131

3232
declare_clippy_lint! {
@@ -1002,51 +1002,58 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
10021002
let ty = cx.tcx.type_of(def_id);
10031003
if_chain! {
10041004
if let hir::ImplItemKind::Method(ref sig, id) = impl_item.node;
1005-
if let Some(first_arg_ty) = sig.decl.inputs.get(0);
10061005
if let Some(first_arg) = iter_input_pats(&sig.decl, cx.tcx.hir().body(id)).next();
1007-
if let hir::ItemKind::Impl(_, _, _, _, None, ref self_ty, _) = item.node;
1006+
if let hir::ItemKind::Impl(_, _, _, _, None, _, _) = item.node;
10081007
then {
1009-
if cx.access_levels.is_exported(impl_item.hir_id) {
1010-
// check missing trait implementations
1011-
for &(method_name, n_args, self_kind, out_type, trait_name) in &TRAIT_METHODS {
1012-
if name == method_name &&
1013-
sig.decl.inputs.len() == n_args &&
1014-
out_type.matches(cx, &sig.decl.output) &&
1015-
self_kind.matches(cx, first_arg_ty, first_arg, self_ty, false, &impl_item.generics) {
1016-
span_lint(cx, SHOULD_IMPLEMENT_TRAIT, impl_item.span, &format!(
1017-
"defining a method called `{}` on this type; consider implementing \
1018-
the `{}` trait or choosing a less ambiguous name", name, trait_name));
1019-
}
1020-
}
1021-
}
1008+
let method_def_id = cx.tcx.hir().local_def_id(impl_item.hir_id);
1009+
let method_sig = cx.tcx.fn_sig(method_def_id);
1010+
let method_sig = cx.tcx.erase_late_bound_regions(&method_sig);
1011+
1012+
let first_arg_ty = &method_sig.inputs().iter().next();
10221013

10231014
// check conventions w.r.t. conversion method names and predicates
1024-
let is_copy = is_copy(cx, ty);
1025-
for &(ref conv, self_kinds) in &CONVENTIONS {
1026-
if conv.check(&name) {
1027-
if !self_kinds
1028-
.iter()
1029-
.any(|k| k.matches(cx, first_arg_ty, first_arg, self_ty, is_copy, &impl_item.generics)) {
1030-
let lint = if item.vis.node.is_pub() {
1031-
WRONG_PUB_SELF_CONVENTION
1032-
} else {
1033-
WRONG_SELF_CONVENTION
1034-
};
1035-
span_lint(cx,
1036-
lint,
1037-
first_arg.pat.span,
1038-
&format!("methods called `{}` usually take {}; consider choosing a less \
1039-
ambiguous name",
1040-
conv,
1041-
&self_kinds.iter()
1042-
.map(|k| k.description())
1043-
.collect::<Vec<_>>()
1044-
.join(" or ")));
1015+
if let Some(first_arg_ty) = first_arg_ty {
1016+
1017+
if cx.access_levels.is_exported(impl_item.hir_id) {
1018+
// check missing trait implementations
1019+
for &(method_name, n_args, self_kind, out_type, trait_name) in &TRAIT_METHODS {
1020+
if name == method_name &&
1021+
sig.decl.inputs.len() == n_args &&
1022+
out_type.matches(cx, &sig.decl.output) &&
1023+
self_kind.matches(cx, ty, first_arg_ty) {
1024+
span_lint(cx, SHOULD_IMPLEMENT_TRAIT, impl_item.span, &format!(
1025+
"defining a method called `{}` on this type; consider implementing \
1026+
the `{}` trait or choosing a less ambiguous name", name, trait_name));
1027+
}
10451028
}
1029+
}
10461030

1047-
// Only check the first convention to match (CONVENTIONS should be listed from most to least
1048-
// specific)
1049-
break;
1031+
for &(ref conv, self_kinds) in &CONVENTIONS {
1032+
if conv.check(&name) {
1033+
if !self_kinds
1034+
.iter()
1035+
.any(|k| k.matches(cx, ty, first_arg_ty)) {
1036+
let lint = if item.vis.node.is_pub() {
1037+
WRONG_PUB_SELF_CONVENTION
1038+
} else {
1039+
WRONG_SELF_CONVENTION
1040+
};
1041+
span_lint(cx,
1042+
lint,
1043+
first_arg.pat.span,
1044+
&format!("methods called `{}` usually take {}; consider choosing a less \
1045+
ambiguous name",
1046+
conv,
1047+
&self_kinds.iter()
1048+
.map(|k| k.description())
1049+
.collect::<Vec<_>>()
1050+
.join(" or ")));
1051+
}
1052+
1053+
// Only check the first convention to match (CONVENTIONS should be listed from most to least
1054+
// specific)
1055+
break;
1056+
}
10501057
}
10511058
}
10521059
}
@@ -2539,55 +2546,33 @@ enum SelfKind {
25392546
}
25402547

25412548
impl SelfKind {
2542-
fn matches(
2543-
self,
2544-
cx: &LateContext<'_, '_>,
2545-
ty: &hir::Ty,
2546-
arg: &hir::Arg,
2547-
self_ty: &hir::Ty,
2548-
allow_value_for_ref: bool,
2549-
generics: &hir::Generics,
2550-
) -> bool {
2551-
// Self types in the HIR are desugared to explicit self types. So it will
2552-
// always be `self:
2553-
// SomeType`,
2554-
// where SomeType can be `Self` or an explicit impl self type (e.g., `Foo` if
2555-
// the impl is on `Foo`)
2556-
// Thus, we only need to test equality against the impl self type or if it is
2557-
// an explicit
2558-
// `Self`. Furthermore, the only possible types for `self: ` are `&Self`,
2559-
// `Self`, `&mut Self`,
2560-
// and `Box<Self>`, including the equivalent types with `Foo`.
2561-
2562-
let is_actually_self = |ty| is_self_ty(ty) || SpanlessEq::new(cx).eq_ty(ty, self_ty);
2563-
if is_self(arg) {
2564-
match self {
2565-
Self::Value => is_actually_self(ty),
2566-
Self::Ref | Self::RefMut => {
2567-
if allow_value_for_ref && is_actually_self(ty) {
2568-
return true;
2569-
}
2570-
match ty.node {
2571-
hir::TyKind::Rptr(_, ref mt_ty) => {
2572-
let mutability_match = if self == Self::Ref {
2573-
mt_ty.mutbl == hir::MutImmutable
2574-
} else {
2575-
mt_ty.mutbl == hir::MutMutable
2576-
};
2577-
is_actually_self(&mt_ty.ty) && mutability_match
2578-
},
2579-
_ => false,
2580-
}
2581-
},
2582-
_ => false,
2583-
}
2584-
} else {
2585-
match self {
2586-
Self::Value => false,
2587-
Self::Ref => is_as_ref_or_mut_trait(ty, self_ty, generics, &paths::ASREF_TRAIT),
2588-
Self::RefMut => is_as_ref_or_mut_trait(ty, self_ty, generics, &paths::ASMUT_TRAIT),
2589-
Self::No => true,
2549+
fn matches<'a>(self, cx: &LateContext<'_, 'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
2550+
fn matches_ref<'a>(
2551+
cx: &LateContext<'_, 'a>,
2552+
mutability: hir::Mutability,
2553+
parent_ty: Ty<'a>,
2554+
ty: Ty<'a>,
2555+
) -> bool {
2556+
if let ty::Ref(_, t, m) = ty.sty {
2557+
return m == mutability && t == parent_ty;
25902558
}
2559+
2560+
let trait_path = match mutability {
2561+
hir::Mutability::MutImmutable => &paths::ASREF_TRAIT,
2562+
hir::Mutability::MutMutable => &paths::ASMUT_TRAIT,
2563+
};
2564+
2565+
let trait_def_id = get_trait_def_id(cx, trait_path).expect("trait def id not found");
2566+
implements_trait(cx, ty, trait_def_id, &[parent_ty.into()])
2567+
}
2568+
2569+
match self {
2570+
Self::Value => ty == parent_ty,
2571+
Self::Ref => {
2572+
matches_ref(cx, hir::Mutability::MutImmutable, parent_ty, ty) || ty == parent_ty && is_copy(cx, ty)
2573+
},
2574+
Self::RefMut => matches_ref(cx, hir::Mutability::MutMutable, parent_ty, ty),
2575+
Self::No => ty != parent_ty,
25912576
}
25922577
}
25932578

@@ -2601,68 +2586,6 @@ impl SelfKind {
26012586
}
26022587
}
26032588

2604-
fn is_as_ref_or_mut_trait(ty: &hir::Ty, self_ty: &hir::Ty, generics: &hir::Generics, name: &[&str]) -> bool {
2605-
single_segment_ty(ty).map_or(false, |seg| {
2606-
generics.params.iter().any(|param| match param.kind {
2607-
hir::GenericParamKind::Type { .. } => {
2608-
param.name.ident().name == seg.ident.name
2609-
&& param.bounds.iter().any(|bound| {
2610-
if let hir::GenericBound::Trait(ref ptr, ..) = *bound {
2611-
let path = &ptr.trait_ref.path;
2612-
match_path(path, name)
2613-
&& path.segments.last().map_or(false, |s| {
2614-
if let Some(ref params) = s.args {
2615-
if params.parenthesized {
2616-
false
2617-
} else {
2618-
// FIXME(flip1995): messy, improve if there is a better option
2619-
// in the compiler
2620-
let types: Vec<_> = params
2621-
.args
2622-
.iter()
2623-
.filter_map(|arg| match arg {
2624-
hir::GenericArg::Type(ty) => Some(ty),
2625-
_ => None,
2626-
})
2627-
.collect();
2628-
types.len() == 1 && (is_self_ty(&types[0]) || is_ty(&*types[0], self_ty))
2629-
}
2630-
} else {
2631-
false
2632-
}
2633-
})
2634-
} else {
2635-
false
2636-
}
2637-
})
2638-
},
2639-
_ => false,
2640-
})
2641-
})
2642-
}
2643-
2644-
fn is_ty(ty: &hir::Ty, self_ty: &hir::Ty) -> bool {
2645-
match (&ty.node, &self_ty.node) {
2646-
(
2647-
&hir::TyKind::Path(hir::QPath::Resolved(_, ref ty_path)),
2648-
&hir::TyKind::Path(hir::QPath::Resolved(_, ref self_ty_path)),
2649-
) => ty_path
2650-
.segments
2651-
.iter()
2652-
.map(|seg| seg.ident.name)
2653-
.eq(self_ty_path.segments.iter().map(|seg| seg.ident.name)),
2654-
_ => false,
2655-
}
2656-
}
2657-
2658-
fn single_segment_ty(ty: &hir::Ty) -> Option<&hir::PathSegment> {
2659-
if let hir::TyKind::Path(ref path) = ty.node {
2660-
single_segment_path(path)
2661-
} else {
2662-
None
2663-
}
2664-
}
2665-
26662589
impl Convention {
26672590
fn check(&self, other: &str) -> bool {
26682591
match *self {

0 commit comments

Comments
 (0)