Skip to content

Commit

Permalink
Auto merge of rust-lang#7403 - Anthuang:redundant-method-names, r=Man…
Browse files Browse the repository at this point in the history
…ishearth

New lint: [`self_named_constructor`]

Adds the `self_named_constructor` lint for detecting when an implemented method has the same name as the type it is implemented for.

changelog: [`self_named_constructor`]

closes: rust-lang#7142
  • Loading branch information
bors committed Jul 19, 2021
2 parents 46363df + e9e10d2 commit f70a074
Show file tree
Hide file tree
Showing 18 changed files with 252 additions and 64 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2772,6 +2772,7 @@ Released 2018-09-13
[`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push
[`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some
[`self_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_assignment
[`self_named_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructor
[`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
[`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
[`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
Expand Down
6 changes: 6 additions & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ mod regex;
mod repeat_once;
mod returns;
mod self_assignment;
mod self_named_constructor;
mod semicolon_if_nothing_returned;
mod serde_api;
mod shadow;
Expand Down Expand Up @@ -900,6 +901,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
returns::LET_AND_RETURN,
returns::NEEDLESS_RETURN,
self_assignment::SELF_ASSIGNMENT,
self_named_constructor::SELF_NAMED_CONSTRUCTOR,
semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED,
serde_api::SERDE_API_MISUSE,
shadow::SHADOW_REUSE,
Expand Down Expand Up @@ -1406,6 +1408,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(returns::LET_AND_RETURN),
LintId::of(returns::NEEDLESS_RETURN),
LintId::of(self_assignment::SELF_ASSIGNMENT),
LintId::of(self_named_constructor::SELF_NAMED_CONSTRUCTOR),
LintId::of(serde_api::SERDE_API_MISUSE),
LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
Expand Down Expand Up @@ -1559,6 +1562,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
LintId::of(returns::LET_AND_RETURN),
LintId::of(returns::NEEDLESS_RETURN),
LintId::of(self_named_constructor::SELF_NAMED_CONSTRUCTOR),
LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
Expand Down Expand Up @@ -2101,6 +2105,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
let scripts = conf.allowed_scripts.clone();
store.register_early_pass(move || box disallowed_script_idents::DisallowedScriptIdents::new(&scripts));
store.register_late_pass(|| box strlen_on_c_strings::StrlenOnCStrings);
store.register_late_pass(move || box self_named_constructor::SelfNamedConstructor);

}

#[rustfmt::skip]
Expand Down
91 changes: 91 additions & 0 deletions clippy_lints/src/self_named_constructor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::return_ty;
use clippy_utils::ty::{contains_adt_constructor, contains_ty};
use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
/// **What it does:** Warns when constructors have the same name as their types.
///
/// **Why is this bad?** Repeating the name of the type is redundant.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust,ignore
/// struct Foo {}
///
/// impl Foo {
/// pub fn foo() -> Foo {
/// Foo {}
/// }
/// }
/// ```
/// Use instead:
/// ```rust,ignore
/// struct Foo {}
///
/// impl Foo {
/// pub fn new() -> Foo {
/// Foo {}
/// }
/// }
/// ```
pub SELF_NAMED_CONSTRUCTOR,
style,
"method should not have the same name as the type it is implemented for"
}

declare_lint_pass!(SelfNamedConstructor => [SELF_NAMED_CONSTRUCTOR]);

impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructor {
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
match impl_item.kind {
ImplItemKind::Fn(ref sig, _) => {
if sig.decl.implicit_self.has_implicit_self() {
return;
}
},
_ => return,
}

let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
let item = cx.tcx.hir().expect_item(parent);
let self_ty = cx.tcx.type_of(item.def_id);
let ret_ty = return_ty(cx, impl_item.hir_id());

// Do not check trait impls
if matches!(item.kind, ItemKind::Impl(Impl { of_trait: Some(_), .. })) {
return;
}

// Ensure method is constructor-like
if let Some(self_adt) = self_ty.ty_adt_def() {
if !contains_adt_constructor(ret_ty, self_adt) {
return;
}
} else if !contains_ty(ret_ty, self_ty) {
return;
}

if_chain! {
if let Some(self_def) = self_ty.ty_adt_def();
if let Some(self_local_did) = self_def.did.as_local();
let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did);
if let Some(Node::Item(x)) = cx.tcx.hir().find(self_id);
let type_name = x.ident.name.as_str().to_lowercase();
if impl_item.ident.name.as_str() == type_name || impl_item.ident.name.as_str().replace("_", "") == type_name;

then {
span_lint(
cx,
SELF_NAMED_CONSTRUCTOR,
impl_item.span,
&format!("constructor `{}` has the same name as the type", impl_item.ident.name),
);
}
}
}
}
2 changes: 1 addition & 1 deletion tests/ui/crashes/ice-6179.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
struct Foo {}

impl Foo {
fn foo() -> Self {
fn new() -> Self {
impl Foo {
fn bar() {}
}
Expand Down
4 changes: 3 additions & 1 deletion tests/ui/issue_4266.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ async fn all_to_one<'a>(a: &'a str, _b: &'a str) -> &'a str {
struct Foo;
impl Foo {
// ok
pub async fn foo(&mut self) {}
pub async fn new(&mut self) -> Self {
Foo {}
}
}

// rust-lang/rust#61115
Expand Down
4 changes: 3 additions & 1 deletion tests/ui/missing-doc-impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ pub trait E: Sized {
}

impl Foo {
pub fn foo() {}
pub fn new() -> Self {
Foo { a: 0, b: 0 }
}
fn bar() {}
}

Expand Down
12 changes: 7 additions & 5 deletions tests/ui/missing-doc-impl.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -78,23 +78,25 @@ LL | type AssociatedTypeDef = Self;
error: missing documentation for an associated function
--> $DIR/missing-doc-impl.rs:62:5
|
LL | pub fn foo() {}
| ^^^^^^^^^^^^^^^
LL | / pub fn new() -> Self {
LL | | Foo { a: 0, b: 0 }
LL | | }
| |_____^

error: missing documentation for an associated function
--> $DIR/missing-doc-impl.rs:63:5
--> $DIR/missing-doc-impl.rs:65:5
|
LL | fn bar() {}
| ^^^^^^^^^^^

error: missing documentation for an associated function
--> $DIR/missing-doc-impl.rs:67:5
--> $DIR/missing-doc-impl.rs:69:5
|
LL | pub fn foo() {}
| ^^^^^^^^^^^^^^^

error: missing documentation for an associated function
--> $DIR/missing-doc-impl.rs:71:5
--> $DIR/missing-doc-impl.rs:73:5
|
LL | / fn foo2() -> u32 {
LL | | 1
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/missing_const_for_fn/cant_be_const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ mod with_drop {

impl A {
// This can not be const because the type implements `Drop`.
pub fn a(self) -> B {
pub fn b(self) -> B {
B
}
}
Expand Down
3 changes: 2 additions & 1 deletion tests/ui/needless_bool/fixable.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
dead_code,
clippy::no_effect,
clippy::if_same_then_else,
clippy::needless_return
clippy::needless_return,
clippy::self_named_constructor
)]

use std::cell::Cell;
Expand Down
3 changes: 2 additions & 1 deletion tests/ui/needless_bool/fixable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
dead_code,
clippy::no_effect,
clippy::if_same_then_else,
clippy::needless_return
clippy::needless_return,
clippy::self_named_constructor
)]

use std::cell::Cell;
Expand Down
24 changes: 12 additions & 12 deletions tests/ui/needless_bool/fixable.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: this if-then-else expression returns a bool literal
--> $DIR/fixable.rs:39:5
--> $DIR/fixable.rs:40:5
|
LL | / if x {
LL | | true
Expand All @@ -11,7 +11,7 @@ LL | | };
= note: `-D clippy::needless-bool` implied by `-D warnings`

error: this if-then-else expression returns a bool literal
--> $DIR/fixable.rs:44:5
--> $DIR/fixable.rs:45:5
|
LL | / if x {
LL | | false
Expand All @@ -21,7 +21,7 @@ LL | | };
| |_____^ help: you can reduce it to: `!x`

error: this if-then-else expression returns a bool literal
--> $DIR/fixable.rs:49:5
--> $DIR/fixable.rs:50:5
|
LL | / if x && y {
LL | | false
Expand All @@ -31,7 +31,7 @@ LL | | };
| |_____^ help: you can reduce it to: `!(x && y)`

error: this if-then-else expression returns a bool literal
--> $DIR/fixable.rs:69:5
--> $DIR/fixable.rs:70:5
|
LL | / if x {
LL | | return true;
Expand All @@ -41,7 +41,7 @@ LL | | };
| |_____^ help: you can reduce it to: `return x`

error: this if-then-else expression returns a bool literal
--> $DIR/fixable.rs:77:5
--> $DIR/fixable.rs:78:5
|
LL | / if x {
LL | | return false;
Expand All @@ -51,7 +51,7 @@ LL | | };
| |_____^ help: you can reduce it to: `return !x`

error: this if-then-else expression returns a bool literal
--> $DIR/fixable.rs:85:5
--> $DIR/fixable.rs:86:5
|
LL | / if x && y {
LL | | return true;
Expand All @@ -61,7 +61,7 @@ LL | | };
| |_____^ help: you can reduce it to: `return x && y`

error: this if-then-else expression returns a bool literal
--> $DIR/fixable.rs:93:5
--> $DIR/fixable.rs:94:5
|
LL | / if x && y {
LL | | return false;
Expand All @@ -71,33 +71,33 @@ LL | | };
| |_____^ help: you can reduce it to: `return !(x && y)`

error: equality checks against true are unnecessary
--> $DIR/fixable.rs:101:8
--> $DIR/fixable.rs:102:8
|
LL | if x == true {};
| ^^^^^^^^^ help: try simplifying it as shown: `x`
|
= note: `-D clippy::bool-comparison` implied by `-D warnings`

error: equality checks against false can be replaced by a negation
--> $DIR/fixable.rs:105:8
--> $DIR/fixable.rs:106:8
|
LL | if x == false {};
| ^^^^^^^^^^ help: try simplifying it as shown: `!x`

error: equality checks against true are unnecessary
--> $DIR/fixable.rs:115:8
--> $DIR/fixable.rs:116:8
|
LL | if x == true {};
| ^^^^^^^^^ help: try simplifying it as shown: `x`

error: equality checks against false can be replaced by a negation
--> $DIR/fixable.rs:116:8
--> $DIR/fixable.rs:117:8
|
LL | if x == false {};
| ^^^^^^^^^^ help: try simplifying it as shown: `!x`

error: this if-then-else expression returns a bool literal
--> $DIR/fixable.rs:125:12
--> $DIR/fixable.rs:126:12
|
LL | } else if returns_bool() {
| ____________^
Expand Down
59 changes: 59 additions & 0 deletions tests/ui/self_named_constructor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#![warn(clippy::self_named_constructor)]

struct ShouldSpawn;
struct ShouldNotSpawn;

impl ShouldSpawn {
pub fn should_spawn() -> ShouldSpawn {
ShouldSpawn
}

fn should_not_spawn() -> ShouldNotSpawn {
ShouldNotSpawn
}
}

impl ShouldNotSpawn {
pub fn new() -> ShouldNotSpawn {
ShouldNotSpawn
}
}

struct ShouldNotSpawnWithTrait;

trait ShouldNotSpawnTrait {
type Item;
}

impl ShouldNotSpawnTrait for ShouldNotSpawnWithTrait {
type Item = Self;
}

impl ShouldNotSpawnWithTrait {
pub fn should_not_spawn_with_trait() -> impl ShouldNotSpawnTrait<Item = Self> {
ShouldNotSpawnWithTrait
}
}

// Same trait name and same type name should not spawn the lint
#[derive(Default)]
pub struct Default;

trait TraitSameTypeName {
fn should_not_spawn() -> Self;
}
impl TraitSameTypeName for ShouldNotSpawn {
fn should_not_spawn() -> Self {
ShouldNotSpawn
}
}

struct SelfMethodShouldNotSpawn;

impl SelfMethodShouldNotSpawn {
fn self_method_should_not_spawn(self) -> Self {
SelfMethodShouldNotSpawn
}
}

fn main() {}
Loading

0 comments on commit f70a074

Please sign in to comment.