Skip to content

Commit a5e4805

Browse files
committed
new_ret_no_self correctly lint impl return
1 parent 2ef4af7 commit a5e4805

File tree

3 files changed

+59
-14
lines changed

3 files changed

+59
-14
lines changed

clippy_lints/src/methods/mod.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use crate::rustc::hir;
1212
use crate::rustc::hir::def::Def;
1313
use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, Lint, LintArray, LintContext, LintPass};
14-
use crate::rustc::ty::{self, Ty};
14+
use crate::rustc::ty::{self, Ty, TyKind, Predicate};
1515
use crate::rustc::{declare_tool_lint, lint_array};
1616
use crate::rustc_errors::Applicability;
1717
use crate::syntax::ast;
@@ -933,9 +933,27 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
933933

934934
if let hir::ImplItemKind::Method(_, _) = implitem.node {
935935
let ret_ty = return_ty(cx, implitem.id);
936-
if name == "new" &&
937-
!same_tys(cx, ret_ty, ty) &&
938-
!ret_ty.is_impl_trait() {
936+
937+
// if return type is impl trait
938+
if let TyKind::Opaque(def_id, _) = ret_ty.sty {
939+
940+
// then one of the associated types must be Self
941+
for predicate in cx.tcx.predicates_of(def_id).predicates.iter() {
942+
match predicate {
943+
(Predicate::Projection(poly_projection_predicate), _) => {
944+
let binder = poly_projection_predicate.ty();
945+
let associated_type = binder.skip_binder();
946+
let associated_type_is_self_type = same_tys(cx, ty, associated_type);
947+
948+
// if the associated type is self, early return and do not trigger lint
949+
if associated_type_is_self_type { return; }
950+
},
951+
(_, _) => {},
952+
}
953+
}
954+
}
955+
956+
if name == "new" && !same_tys(cx, ret_ty, ty) {
939957
span_lint(cx,
940958
NEW_RET_NO_SELF,
941959
implitem.span,

tests/ui/new_ret_no_self.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ trait R {
99
type Item;
1010
}
1111

12+
trait Q {
13+
type Item;
14+
type Item2;
15+
}
16+
1217
struct S;
1318

1419
impl R for S {
@@ -42,12 +47,26 @@ impl R for S3 {
4247
}
4348

4449
impl S3 {
45-
// should trigger the lint, but currently does not
50+
// should trigger the lint
4651
pub fn new(_: String) -> impl R<Item = u32> {
4752
S3
4853
}
4954
}
5055

56+
struct S4;
57+
58+
impl Q for S4 {
59+
type Item = u32;
60+
type Item2 = Self;
61+
}
62+
63+
impl S4 {
64+
// should not trigger the lint
65+
pub fn new(_: String) -> impl Q<Item = u32, Item2 = Self> {
66+
S4
67+
}
68+
}
69+
5170
struct T;
5271

5372
impl T {

tests/ui/new_ret_no_self.stderr

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
11
error: methods called `new` usually return `Self`
2-
--> $DIR/new_ret_no_self.rs:64:5
2+
--> $DIR/new_ret_no_self.rs:51:5
33
|
4-
64 | / pub fn new() -> u32 {
5-
65 | | unimplemented!();
6-
66 | | }
4+
51 | / pub fn new(_: String) -> impl R<Item = u32> {
5+
52 | | S3
6+
53 | | }
77
| |_____^
88
|
99
= note: `-D clippy::new-ret-no-self` implied by `-D warnings`
1010

1111
error: methods called `new` usually return `Self`
12-
--> $DIR/new_ret_no_self.rs:73:5
12+
--> $DIR/new_ret_no_self.rs:83:5
1313
|
14-
73 | / pub fn new(_: String) -> u32 {
15-
74 | | unimplemented!();
16-
75 | | }
14+
83 | / pub fn new() -> u32 {
15+
84 | | unimplemented!();
16+
85 | | }
1717
| |_____^
1818

19-
error: aborting due to 2 previous errors
19+
error: methods called `new` usually return `Self`
20+
--> $DIR/new_ret_no_self.rs:92:5
21+
|
22+
92 | / pub fn new(_: String) -> u32 {
23+
93 | | unimplemented!();
24+
94 | | }
25+
| |_____^
26+
27+
error: aborting due to 3 previous errors
2028

0 commit comments

Comments
 (0)