Merge pull request #3253 from JoshMcguigan/new_ret_no_self-3220

new_ret_no_self
This commit is contained in:
Oliver S̶c̶h̶n̶e̶i̶d̶e̶r Scherer 2018-10-13 20:10:51 +02:00 committed by GitHub
commit 6812c0c86d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 157 additions and 22 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;
@ -878,6 +878,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
let name = implitem.ident.name;
let parent = cx.tcx.hir.get_parent(implitem.id);
let item = cx.tcx.hir.expect_item(parent);
let def_id = cx.tcx.hir.local_def_id(item.id);
let ty = cx.tcx.type_of(def_id);
if_chain! {
if let hir::ImplItemKind::Method(ref sig, id) = implitem.node;
if let Some(first_arg_ty) = sig.decl.inputs.get(0);
@ -899,8 +901,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
}
// check conventions w.r.t. conversion method names and predicates
let def_id = cx.tcx.hir.local_def_id(item.id);
let ty = cx.tcx.type_of(def_id);
let is_copy = is_copy(cx, ty);
for &(ref conv, self_kinds) in &CONVENTIONS {
if conv.check(&name.as_str()) {
@ -928,16 +928,37 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
break;
}
}
}
}
let ret_ty = return_ty(cx, implitem.id);
if name == "new" &&
!ret_ty.walk().any(|t| same_tys(cx, t, ty)) {
span_lint(cx,
NEW_RET_NO_SELF,
implitem.span,
"methods called `new` usually return `Self`");
if let hir::ImplItemKind::Method(_, _) = implitem.node {
let ret_ty = return_ty(cx, implitem.id);
// 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,
"methods called `new` usually return `Self`");
}
}
}
}

View File

@ -1920,6 +1920,7 @@ enum ImplicitHasherType<'tcx> {
impl<'tcx> ImplicitHasherType<'tcx> {
/// Checks that `ty` is a target type without a BuildHasher.
#[allow(clippy::new_ret_no_self)]
fn new<'a>(cx: &LateContext<'a, 'tcx>, hir_ty: &hir::Ty) -> Option<Self> {
if let TyKind::Path(QPath::Resolved(None, ref path)) = hir_ty.node {
let params: Vec<_> = path.segments.last().as_ref()?.args.as_ref()?

View File

@ -14,7 +14,7 @@
#![warn(clippy::all, clippy::pedantic, clippy::option_unwrap_used)]
#![allow(clippy::blacklisted_name, unused, clippy::print_stdout, clippy::non_ascii_literal, clippy::new_without_default,
clippy::new_without_default_derive, clippy::missing_docs_in_private_items, clippy::needless_pass_by_value,
clippy::default_trait_access, clippy::use_self, clippy::useless_format)]
clippy::default_trait_access, clippy::use_self, clippy::new_ret_no_self, clippy::useless_format)]
use std::collections::BTreeMap;
use std::collections::HashMap;
@ -43,7 +43,7 @@ impl T {
fn to_something(self) -> u32 { 0 }
fn new(self) {}
fn new(self) -> Self { unimplemented!(); }
}
struct Lt<'a> {

View File

@ -23,17 +23,9 @@ error: methods called `to_*` usually take self by reference; consider choosing a
error: methods called `new` usually take no self; consider choosing a less ambiguous name
--> $DIR/methods.rs:46:12
|
46 | fn new(self) {}
46 | fn new(self) -> Self { unimplemented!(); }
| ^^^^
error: methods called `new` usually return `Self`
--> $DIR/methods.rs:46:5
|
46 | fn new(self) {}
| ^^^^^^^^^^^^^^^
|
= note: `-D clippy::new-ret-no-self` implied by `-D warnings`
error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead
--> $DIR/methods.rs:114:13
|
@ -465,5 +457,5 @@ error: used unwrap() on an Option value. If you don't want to handle the None ca
|
= note: `-D clippy::option-unwrap-used` implied by `-D warnings`
error: aborting due to 58 previous errors
error: aborting due to 57 previous errors

View File

@ -0,0 +1,93 @@
#![warn(clippy::new_ret_no_self)]
#![allow(dead_code, clippy::trivially_copy_pass_by_ref)]
fn main(){}
trait R {
type Item;
}
trait Q {
type Item;
type Item2;
}
struct S;
impl R for S {
type Item = Self;
}
impl S {
// should not trigger the lint
pub fn new() -> impl R<Item = Self> {
S
}
}
struct S2;
impl R for S2 {
type Item = Self;
}
impl S2 {
// should not trigger the lint
pub fn new(_: String) -> impl R<Item = Self> {
S2
}
}
struct S3;
impl R for S3 {
type Item = u32;
}
impl S3 {
// 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 {
// should not trigger lint
pub fn new() -> Self {
unimplemented!();
}
}
struct U;
impl U {
// should trigger lint
pub fn new() -> u32 {
unimplemented!();
}
}
struct V;
impl V {
// should trigger lint
pub fn new(_: String) -> u32 {
unimplemented!();
}
}

View File

@ -0,0 +1,28 @@
error: methods called `new` usually return `Self`
--> $DIR/new_ret_no_self.rs:49:5
|
49 | / pub fn new(_: String) -> impl R<Item = u32> {
50 | | S3
51 | | }
| |_____^
|
= note: `-D clippy::new-ret-no-self` implied by `-D warnings`
error: methods called `new` usually return `Self`
--> $DIR/new_ret_no_self.rs:81:5
|
81 | / pub fn new() -> u32 {
82 | | unimplemented!();
83 | | }
| |_____^
error: methods called `new` usually return `Self`
--> $DIR/new_ret_no_self.rs:90:5
|
90 | / pub fn new(_: String) -> u32 {
91 | | unimplemented!();
92 | | }
| |_____^
error: aborting due to 3 previous errors