Skip to content

Commit ff799fa

Browse files
committed
Lint about new methods not returning Self
1 parent edc0d19 commit ff799fa

File tree

4 files changed

+49
-3
lines changed

4 files changed

+49
-3
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code.
66
[Jump to usage instructions](#usage)
77

88
##Lints
9-
There are 120 lints included in this crate:
9+
There are 121 lints included in this crate:
1010

1111
name | default | meaning
1212
---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -76,6 +76,7 @@ name
7676
[needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do
7777
[needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice
7878
[needless_update](https://github.com/Manishearth/rust-clippy/wiki#needless_update) | warn | using `{ ..base }` when there are no missing fields
79+
[new_ret_no_self](https://github.com/Manishearth/rust-clippy/wiki#new_ret_no_self) | warn | not returning `Self` in a `new` method
7980
[no_effect](https://github.com/Manishearth/rust-clippy/wiki#no_effect) | warn | statements with no effect
8081
[non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead
8182
[nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
234234
methods::CLONE_ON_COPY,
235235
methods::EXTEND_FROM_SLICE,
236236
methods::FILTER_NEXT,
237+
methods::NEW_RET_NO_SELF,
237238
methods::OK_EXPECT,
238239
methods::OPTION_MAP_UNWRAP_OR,
239240
methods::OPTION_MAP_UNWRAP_OR_ELSE,

src/methods.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,23 @@ declare_lint! {
278278
pub CLONE_DOUBLE_REF, Warn, "using `clone` on `&&T`"
279279
}
280280

281+
/// **What it does:** This lint warns about `new` not returning `Self`.
282+
///
283+
/// **Why is this bad?** As a convention, `new` methods are used to make a new instance of a type.
284+
///
285+
/// **Known problems:** None.
286+
///
287+
/// **Example:**
288+
/// ```rust
289+
/// impl Foo {
290+
/// fn new(..) -> NotAFoo {
291+
/// }
292+
/// }
293+
/// ```
294+
declare_lint! {
295+
pub NEW_RET_NO_SELF, Warn, "not returning `Self` in a `new` method"
296+
}
297+
281298
impl LintPass for MethodsPass {
282299
fn get_lints(&self) -> LintArray {
283300
lint_array!(EXTEND_FROM_SLICE,
@@ -294,7 +311,8 @@ impl LintPass for MethodsPass {
294311
OR_FUN_CALL,
295312
CHARS_NEXT_CMP,
296313
CLONE_ON_COPY,
297-
CLONE_DOUBLE_REF)
314+
CLONE_DOUBLE_REF,
315+
NEW_RET_NO_SELF)
298316
}
299317
}
300318

@@ -390,6 +408,29 @@ impl LateLintPass for MethodsPass {
390408
.join(" or ")));
391409
}
392410
}
411+
412+
if &name.as_str() == &"new" {
413+
let returns_self = if let FunctionRetTy::Return(ref ret_ty) = sig.decl.output {
414+
let ast_ty_to_ty_cache = cx.tcx.ast_ty_to_ty_cache.borrow();
415+
let ty = ast_ty_to_ty_cache.get(&ty.id);
416+
let ret_ty = ast_ty_to_ty_cache.get(&ret_ty.id);
417+
418+
match (ty, ret_ty) {
419+
(Some(&ty), Some(&ret_ty)) => ty == ret_ty,
420+
_ => false,
421+
}
422+
}
423+
else {
424+
false
425+
};
426+
427+
if !returns_self {
428+
span_lint(cx,
429+
NEW_RET_NO_SELF,
430+
sig.explicit_self.span,
431+
"methods called `new` usually return `Self`");
432+
}
433+
}
393434
}
394435
}
395436
}

tests/compile-fail/methods.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,16 @@ impl T {
2323

2424
fn to_something(self) -> u32 { 0 } //~ERROR methods called `to_*` usually take self by reference
2525

26-
fn new(self) {} //~ERROR methods called `new` usually take no self
26+
fn new(self) {}
27+
//~^ ERROR methods called `new` usually take no self
28+
//~| ERROR methods called `new` usually return `Self`
2729
}
2830

2931
#[derive(Clone,Copy)]
3032
struct U;
3133

3234
impl U {
35+
fn new() -> Self { U }
3336
fn to_something(self) -> u32 { 0 } // ok because U is Copy
3437
}
3538

0 commit comments

Comments
 (0)