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;
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,
type Item;
}
+trait Q {
+ type Item;
+ type Item2;
+}
+
struct S;
impl R for S {
}
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 {
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