new_ret_no_self correctly lint impl return

This commit is contained in:
Josh Mcguigan 2018-10-04 19:01:04 -07:00
parent 2ef4af7db2
commit a5e4805ecf
3 changed files with 59 additions and 14 deletions

View file

@ -11,7 +11,7 @@
use crate::rustc::hir;
use crate::rustc::hir::def::Def;
use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, Lint, LintArray, LintContext, LintPass};
use crate::rustc::ty::{self, Ty};
use crate::rustc::ty::{self, Ty, TyKind, Predicate};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::syntax::ast;
@ -933,9 +933,27 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
if let hir::ImplItemKind::Method(_, _) = implitem.node {
let ret_ty = return_ty(cx, implitem.id);
if name == "new" &&
!same_tys(cx, ret_ty, ty) &&
!ret_ty.is_impl_trait() {
// if return type is impl trait
if let TyKind::Opaque(def_id, _) = ret_ty.sty {
// then one of the associated types must be Self
for predicate in cx.tcx.predicates_of(def_id).predicates.iter() {
match predicate {
(Predicate::Projection(poly_projection_predicate), _) => {
let binder = poly_projection_predicate.ty();
let associated_type = binder.skip_binder();
let associated_type_is_self_type = same_tys(cx, ty, associated_type);
// if the associated type is self, early return and do not trigger lint
if associated_type_is_self_type { return; }
},
(_, _) => {},
}
}
}
if name == "new" && !same_tys(cx, ret_ty, ty) {
span_lint(cx,
NEW_RET_NO_SELF,
implitem.span,

View file

@ -9,6 +9,11 @@ trait R {
type Item;
}
trait Q {
type Item;
type Item2;
}
struct S;
impl R for S {
@ -42,12 +47,26 @@ impl R for S3 {
}
impl S3 {
// should trigger the lint, but currently does not
// should trigger the lint
pub fn new(_: String) -> impl R<Item = u32> {
S3
}
}
struct S4;
impl Q for S4 {
type Item = u32;
type Item2 = Self;
}
impl S4 {
// should not trigger the lint
pub fn new(_: String) -> impl Q<Item = u32, Item2 = Self> {
S4
}
}
struct T;
impl T {

View file

@ -1,20 +1,28 @@
error: methods called `new` usually return `Self`
--> $DIR/new_ret_no_self.rs:64:5
--> $DIR/new_ret_no_self.rs:51:5
|
64 | / pub fn new() -> u32 {
65 | | unimplemented!();
66 | | }
51 | / pub fn new(_: String) -> impl R<Item = u32> {
52 | | S3
53 | | }
| |_____^
|
= note: `-D clippy::new-ret-no-self` implied by `-D warnings`
error: methods called `new` usually return `Self`
--> $DIR/new_ret_no_self.rs:73:5
--> $DIR/new_ret_no_self.rs:83:5
|
73 | / pub fn new(_: String) -> u32 {
74 | | unimplemented!();
75 | | }
83 | / pub fn new() -> u32 {
84 | | unimplemented!();
85 | | }
| |_____^
error: aborting due to 2 previous errors
error: methods called `new` usually return `Self`
--> $DIR/new_ret_no_self.rs:92:5
|
92 | / pub fn new(_: String) -> u32 {
93 | | unimplemented!();
94 | | }
| |_____^
error: aborting due to 3 previous errors