Skip to content

Commit d1eecba

Browse files
authored
Merge pull request #1965 from montrivo/use_self
lint #1674: replace struct name with `Self` when applicable
2 parents d2504fa + 7aebe3a commit d1eecba

File tree

4 files changed

+178
-0
lines changed

4 files changed

+178
-0
lines changed

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ pub mod unicode;
148148
pub mod unsafe_removed_from_name;
149149
pub mod unused_io_amount;
150150
pub mod unused_label;
151+
pub mod use_self;
151152
pub mod vec;
152153
pub mod zero_div_zero;
153154
// end lints modules, do not remove this comment, it’s used in `update_lints`
@@ -319,6 +320,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
319320
reg.register_late_lint_pass(box should_assert_eq::ShouldAssertEq);
320321
reg.register_late_lint_pass(box needless_pass_by_value::NeedlessPassByValue);
321322
reg.register_early_lint_pass(box literal_digit_grouping::LiteralDigitGrouping);
323+
reg.register_late_lint_pass(box use_self::UseSelf);
322324

323325
reg.register_lint_group("clippy_restrictions", vec![
324326
arithmetic::FLOAT_ARITHMETIC,

clippy_lints/src/use_self.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
use rustc::lint::{LintArray, LateLintPass, LateContext, LintPass};
2+
use rustc::hir::*;
3+
use rustc::hir::intravisit::{Visitor, walk_path, NestedVisitorMap};
4+
use utils::span_lint_and_then;
5+
use syntax::ast::NodeId;
6+
use syntax_pos::symbol::keywords::SelfType;
7+
8+
/// **What it does:** Checks for unnecessary repetition of structure name when a
9+
/// replacement with `Self` is applicable.
10+
///
11+
/// **Why is this bad?** Unnecessary repetition. Mixed use of `Self` and struct name
12+
/// feels inconsistent.
13+
///
14+
/// **Known problems:** None.
15+
///
16+
/// **Example:**
17+
/// ```rust
18+
/// struct Foo {}
19+
/// impl Foo {
20+
/// fn new() -> Foo {
21+
/// Foo {}
22+
/// }
23+
/// }
24+
/// ```
25+
/// could be
26+
/// ```
27+
/// struct Foo {}
28+
/// impl Foo {
29+
/// fn new() -> Self {
30+
/// Self {}
31+
/// }
32+
/// }
33+
/// ```
34+
declare_lint! {
35+
pub USE_SELF,
36+
Allow,
37+
"Unnecessary structure name repetition whereas `Self` is applicable"
38+
}
39+
40+
#[derive(Copy, Clone, Default)]
41+
pub struct UseSelf;
42+
43+
impl LintPass for UseSelf {
44+
fn get_lints(&self) -> LintArray {
45+
lint_array!(USE_SELF)
46+
}
47+
}
48+
49+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf {
50+
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
51+
if_let_chain!([
52+
let ItemImpl(.., ref item_type, ref refs) = item.node,
53+
let Ty_::TyPath(QPath::Resolved(_, ref item_path)) = item_type.node,
54+
], {
55+
let visitor = &mut UseSelfVisitor {
56+
item_path: item_path,
57+
cx: cx,
58+
};
59+
for impl_item_ref in refs {
60+
visitor.visit_impl_item(cx.tcx.hir.impl_item(impl_item_ref.id));
61+
}
62+
})
63+
}
64+
}
65+
66+
struct UseSelfVisitor<'a, 'tcx: 'a> {
67+
item_path: &'a Path,
68+
cx: &'a LateContext<'a, 'tcx>,
69+
}
70+
71+
impl<'a, 'tcx> Visitor<'tcx> for UseSelfVisitor<'a, 'tcx> {
72+
fn visit_path(&mut self, path: &'tcx Path, _id: NodeId) {
73+
if self.item_path.def == path.def &&
74+
path.segments
75+
.last()
76+
.expect("segments should be composed of at least 1 element")
77+
.name != SelfType.name() {
78+
span_lint_and_then(self.cx, USE_SELF, path.span, "unnecessary structure name repetition", |db| {
79+
db.span_suggestion(path.span,
80+
"use the applicable keyword",
81+
"Self".to_owned());
82+
});
83+
}
84+
85+
walk_path(self, path);
86+
}
87+
88+
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
89+
NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir)
90+
}
91+
}

tests/ui/use_self.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#![feature(plugin)]
2+
#![plugin(clippy)]
3+
#![warn(use_self)]
4+
#![allow(dead_code)]
5+
6+
7+
fn main() {}
8+
9+
mod use_self {
10+
struct Foo {}
11+
12+
impl Foo {
13+
fn new() -> Foo {
14+
Foo {}
15+
}
16+
fn test() -> Foo {
17+
Foo::new()
18+
}
19+
}
20+
21+
impl Default for Foo {
22+
fn default() -> Foo {
23+
Foo::new()
24+
}
25+
}
26+
}
27+
28+
mod better {
29+
struct Foo {}
30+
31+
impl Foo {
32+
fn new() -> Self {
33+
Self {}
34+
}
35+
fn test() -> Self {
36+
Self::new()
37+
}
38+
}
39+
40+
impl Default for Foo {
41+
fn default() -> Self {
42+
Self::new()
43+
}
44+
}
45+
}

tests/ui/use_self.stderr

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
error: unnecessary structure name repetition
2+
--> $DIR/use_self.rs:13:21
3+
|
4+
13 | fn new() -> Foo {
5+
| ^^^ help: use the applicable keyword: `Self`
6+
|
7+
= note: `-D use-self` implied by `-D warnings`
8+
9+
error: unnecessary structure name repetition
10+
--> $DIR/use_self.rs:14:13
11+
|
12+
14 | Foo {}
13+
| ^^^ help: use the applicable keyword: `Self`
14+
15+
error: unnecessary structure name repetition
16+
--> $DIR/use_self.rs:16:22
17+
|
18+
16 | fn test() -> Foo {
19+
| ^^^ help: use the applicable keyword: `Self`
20+
21+
error: unnecessary structure name repetition
22+
--> $DIR/use_self.rs:17:13
23+
|
24+
17 | Foo::new()
25+
| ^^^^^^^^ help: use the applicable keyword: `Self`
26+
27+
error: unnecessary structure name repetition
28+
--> $DIR/use_self.rs:22:25
29+
|
30+
22 | fn default() -> Foo {
31+
| ^^^ help: use the applicable keyword: `Self`
32+
33+
error: unnecessary structure name repetition
34+
--> $DIR/use_self.rs:23:13
35+
|
36+
23 | Foo::new()
37+
| ^^^^^^^^ help: use the applicable keyword: `Self`
38+
39+
error: aborting due to 6 previous errors
40+

0 commit comments

Comments
 (0)