Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit a6bb927

Browse files
committed
Lint wrong self convention in trait also
1 parent 6c70133 commit a6bb927

File tree

3 files changed

+101
-8
lines changed

3 files changed

+101
-8
lines changed

clippy_lints/src/methods/mod.rs

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use rustc_semver::RustcVersion;
2222
use rustc_session::{declare_tool_lint, impl_lint_pass};
2323
use rustc_span::source_map::Span;
2424
use rustc_span::symbol::{sym, SymbolStr};
25+
use rustc_typeck::hir_ty_to_ty;
2526

2627
use crate::consts::{constant, Constant};
2728
use crate::utils::eager_or_lazy::is_lazyness_candidate;
@@ -1623,10 +1624,15 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
16231624
let item = cx.tcx.hir().expect_item(parent);
16241625
let def_id = cx.tcx.hir().local_def_id(item.hir_id);
16251626
let self_ty = cx.tcx.type_of(def_id);
1627+
1628+
// if this impl block implements a trait, lint in trait definition instead
1629+
if let hir::ItemKind::Impl { of_trait: Some(_), .. } = item.kind {
1630+
return;
1631+
}
1632+
16261633
if_chain! {
16271634
if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind;
16281635
if let Some(first_arg) = iter_input_pats(&sig.decl, cx.tcx.hir().body(id)).next();
1629-
if let hir::ItemKind::Impl{ of_trait: None, .. } = item.kind;
16301636

16311637
let method_def_id = cx.tcx.hir().local_def_id(impl_item.hir_id);
16321638
let method_sig = cx.tcx.fn_sig(method_def_id);
@@ -1697,11 +1703,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
16971703
}
16981704
}
16991705

1700-
// if this impl block implements a trait, lint in trait definition instead
1701-
if let hir::ItemKind::Impl { of_trait: Some(_), .. } = item.kind {
1702-
return;
1703-
}
1704-
17051706
if let hir::ImplItemKind::Fn(_, _) = impl_item.kind {
17061707
let ret_ty = return_ty(cx, impl_item.hir_id);
17071708

@@ -1735,8 +1736,42 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
17351736
}
17361737

17371738
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
1739+
if in_external_macro(cx.tcx.sess, item.span) {
1740+
return;
1741+
}
1742+
1743+
if_chain! {
1744+
if let TraitItemKind::Fn(ref sig, _) = item.kind;
1745+
if let Some(first_arg_ty) = sig.decl.inputs.iter().next();
1746+
let first_arg_span = first_arg_ty.span;
1747+
let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty);
1748+
let self_ty = TraitRef::identity(cx.tcx, item.hir_id.owner.to_def_id()).self_ty();
1749+
1750+
then {
1751+
if let Some((ref conv, self_kinds)) = &CONVENTIONS
1752+
.iter()
1753+
.find(|(ref conv, _)| conv.check(&item.ident.name.as_str()))
1754+
{
1755+
if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) {
1756+
span_lint(
1757+
cx,
1758+
WRONG_PUB_SELF_CONVENTION,
1759+
first_arg_span,
1760+
&format!("methods called `{}` usually take {}; consider choosing a less ambiguous name",
1761+
conv,
1762+
&self_kinds
1763+
.iter()
1764+
.map(|k| k.description())
1765+
.collect::<Vec<_>>()
1766+
.join(" or ")
1767+
),
1768+
);
1769+
}
1770+
}
1771+
}
1772+
}
1773+
17381774
if_chain! {
1739-
if !in_external_macro(cx.tcx.sess, item.span);
17401775
if item.ident.name == sym::new;
17411776
if let TraitItemKind::Fn(_, _) = item.kind;
17421777
let ret_ty = return_ty(cx, item.hir_id);

tests/ui/wrong_self_convention.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,29 @@ mod issue4037 {
8888
}
8989
}
9090
}
91+
92+
// Lint also in trait definition (see #6307)
93+
mod issue6307{
94+
trait T: Sized {
95+
fn as_i32(self) {}
96+
fn as_u32(&self) {}
97+
fn into_i32(&self) {}
98+
fn into_u32(self) {}
99+
fn is_i32(self) {}
100+
fn is_u32(&self) {}
101+
fn to_i32(self) {}
102+
fn to_u32(&self) {}
103+
fn from_i32(self) {}
104+
// check whether the lint can be allowed at the function level
105+
#[allow(clippy::wrong_pub_self_convention)]
106+
fn from_cake(self) {}
107+
108+
// test for false positives
109+
fn as_(self) {}
110+
fn into_(&self) {}
111+
fn is_(self) {}
112+
fn to_(self) {}
113+
fn from_(self) {}
114+
fn to_mut(&mut self) {}
115+
}
116+
}

tests/ui/wrong_self_convention.stderr

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,5 +72,37 @@ error: methods called `from_*` usually take no self; consider choosing a less am
7272
LL | pub fn from_i64(self) {}
7373
| ^^^^
7474

75-
error: aborting due to 12 previous errors
75+
error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name
76+
--> $DIR/wrong_self_convention.rs:95:19
77+
|
78+
LL | fn as_i32(self) {}
79+
| ^^^^
80+
|
81+
= note: `-D clippy::wrong-pub-self-convention` implied by `-D warnings`
82+
83+
error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name
84+
--> $DIR/wrong_self_convention.rs:97:21
85+
|
86+
LL | fn into_i32(&self) {}
87+
| ^^^^^
88+
89+
error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name
90+
--> $DIR/wrong_self_convention.rs:99:19
91+
|
92+
LL | fn is_i32(self) {}
93+
| ^^^^
94+
95+
error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name
96+
--> $DIR/wrong_self_convention.rs:101:19
97+
|
98+
LL | fn to_i32(self) {}
99+
| ^^^^
100+
101+
error: methods called `from_*` usually take no self; consider choosing a less ambiguous name
102+
--> $DIR/wrong_self_convention.rs:103:21
103+
|
104+
LL | fn from_i32(self) {}
105+
| ^^^^
106+
107+
error: aborting due to 17 previous errors
76108

0 commit comments

Comments
 (0)