Skip to content

Commit 053896b

Browse files
authored
Merge pull request #1307 from Kha/partialeq_ne
Implement 'Re-implementing `PartialEq::ne`' lint
2 parents 8b2e80b + 9314965 commit 053896b

File tree

9 files changed

+93
-24
lines changed

9 files changed

+93
-24
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ All notable changes to this project will be documented in this file.
325325
[`out_of_bounds_indexing`]: https://github.com/Manishearth/rust-clippy/wiki#out_of_bounds_indexing
326326
[`overflow_check_conditional`]: https://github.com/Manishearth/rust-clippy/wiki#overflow_check_conditional
327327
[`panic_params`]: https://github.com/Manishearth/rust-clippy/wiki#panic_params
328+
[`partialeq_ne_impl`]: https://github.com/Manishearth/rust-clippy/wiki#partialeq_ne_impl
328329
[`precedence`]: https://github.com/Manishearth/rust-clippy/wiki#precedence
329330
[`print_stdout`]: https://github.com/Manishearth/rust-clippy/wiki#print_stdout
330331
[`print_with_newline`]: https://github.com/Manishearth/rust-clippy/wiki#print_with_newline

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ You can check out this great service at [clippy.bashy.io](https://clippy.bashy.i
182182

183183
## Lints
184184

185-
There are 175 lints included in this crate:
185+
There are 176 lints included in this crate:
186186

187187
name | default | triggers on
188188
-----------------------------------------------------------------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------
@@ -301,6 +301,7 @@ name
301301
[out_of_bounds_indexing](https://github.com/Manishearth/rust-clippy/wiki#out_of_bounds_indexing) | deny | out of bounds constant indexing
302302
[overflow_check_conditional](https://github.com/Manishearth/rust-clippy/wiki#overflow_check_conditional) | warn | overflow checks inspired by C which are likely to panic
303303
[panic_params](https://github.com/Manishearth/rust-clippy/wiki#panic_params) | warn | missing parameters in `panic!` calls
304+
[partialeq_ne_impl](https://github.com/Manishearth/rust-clippy/wiki#partialeq_ne_impl) | warn | re-implementing `PartialEq::ne`
304305
[precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | operations where precedence may be unclear
305306
[print_stdout](https://github.com/Manishearth/rust-clippy/wiki#print_stdout) | allow | printing on stdout
306307
[print_with_newline](https://github.com/Manishearth/rust-clippy/wiki#print_with_newline) | warn | using `print!()` with a format string that ends in a newline

clippy_lints/src/derive.rs

+3-13
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ use rustc::ty::subst::Subst;
33
use rustc::ty::TypeVariants;
44
use rustc::ty;
55
use rustc::hir::*;
6-
use syntax::ast::{Attribute, MetaItemKind};
76
use syntax::codemap::Span;
87
use utils::paths;
9-
use utils::{match_path, span_lint_and_then};
8+
use utils::{is_automatically_derived, match_path, span_lint_and_then};
109

1110
/// **What it does:** Checks for deriving `Hash` but implementing `PartialEq`
1211
/// explicitly.
@@ -75,7 +74,7 @@ impl LateLintPass for Derive {
7574
fn check_item(&mut self, cx: &LateContext, item: &Item) {
7675
if let ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node {
7776
let ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(item.id)).ty;
78-
let is_automatically_derived = item.attrs.iter().any(is_automatically_derived);
77+
let is_automatically_derived = is_automatically_derived(&*item.attrs);
7978

8079
check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
8180

@@ -97,7 +96,7 @@ fn check_hash_peq<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, span: Span, trait_re
9796

9897
// Look for the PartialEq implementations for `ty`
9998
peq_trait_def.for_each_relevant_impl(cx.tcx, ty, |impl_id| {
100-
let peq_is_automatically_derived = cx.tcx.get_attrs(impl_id).iter().any(is_automatically_derived);
99+
let peq_is_automatically_derived = is_automatically_derived(&cx.tcx.get_attrs(impl_id));
101100

102101
if peq_is_automatically_derived == hash_is_automatically_derived {
103102
return;
@@ -174,12 +173,3 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref
174173
});
175174
}
176175
}
177-
178-
/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d implementations have.
179-
fn is_automatically_derived(attr: &Attribute) -> bool {
180-
if let MetaItemKind::Word(ref word) = attr.node.value.node {
181-
word == &"automatically_derived"
182-
} else {
183-
false
184-
}
185-
}

clippy_lints/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ pub mod ok_if_let;
111111
pub mod open_options;
112112
pub mod overflow_check_conditional;
113113
pub mod panic;
114+
pub mod partialeq_ne_impl;
114115
pub mod precedence;
115116
pub mod print;
116117
pub mod ptr;
@@ -265,6 +266,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
265266
reg.register_late_lint_pass(box missing_doc::MissingDoc::new());
266267
reg.register_late_lint_pass(box ok_if_let::Pass);
267268
reg.register_late_lint_pass(box if_let_redundant_pattern_matching::Pass);
269+
reg.register_late_lint_pass(box partialeq_ne_impl::Pass);
268270

269271
reg.register_lint_group("clippy_restrictions", vec![
270272
arithmetic::FLOAT_ARITHMETIC,
@@ -421,6 +423,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
421423
open_options::NONSENSICAL_OPEN_OPTIONS,
422424
overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
423425
panic::PANIC_PARAMS,
426+
partialeq_ne_impl::PARTIALEQ_NE_IMPL,
424427
precedence::PRECEDENCE,
425428
print::PRINT_WITH_NEWLINE,
426429
ptr::CMP_NULL,

clippy_lints/src/partialeq_ne_impl.rs

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use rustc::lint::*;
2+
use rustc::hir::*;
3+
use utils::{is_automatically_derived, span_lint};
4+
5+
/// **What it does:** Checks for manual re-implementations of `PartialEq::ne`.
6+
///
7+
/// **Why is this bad?** `PartialEq::ne` is required to always return the
8+
/// negated result of `PartialEq::eq`, which is exactly what the default
9+
/// implementation does. Therefore, there should never be any need to
10+
/// re-implement it.
11+
///
12+
/// **Known problems:** None.
13+
///
14+
/// **Example:**
15+
/// ```rust
16+
/// struct Foo;
17+
///
18+
/// impl PartialEq for Foo {
19+
/// fn eq(&self, other: &Foo) -> bool { ... }
20+
/// fn ne(&self, other: &Foo) -> bool { !(self == other) }
21+
/// }
22+
/// ```
23+
declare_lint! {
24+
pub PARTIALEQ_NE_IMPL,
25+
Warn,
26+
"re-implementing `PartialEq::ne`"
27+
}
28+
29+
#[derive(Clone, Copy)]
30+
pub struct Pass;
31+
32+
impl LintPass for Pass {
33+
fn get_lints(&self) -> LintArray {
34+
lint_array!(PARTIALEQ_NE_IMPL)
35+
}
36+
}
37+
38+
impl LateLintPass for Pass {
39+
fn check_item(&mut self, cx: &LateContext, item: &Item) {
40+
if_let_chain! {[
41+
let ItemImpl(_, _, _, Some(ref trait_ref), _, ref impl_items) = item.node,
42+
!is_automatically_derived(&*item.attrs),
43+
cx.tcx.expect_def(trait_ref.ref_id).def_id() == cx.tcx.lang_items.eq_trait().unwrap(),
44+
], {
45+
for impl_item in impl_items {
46+
if &*impl_item.name.as_str() == "ne" {
47+
span_lint(cx,
48+
PARTIALEQ_NE_IMPL,
49+
impl_item.span,
50+
"re-implementing `PartialEq::ne` is unnecessary")
51+
}
52+
}
53+
}};
54+
}
55+
}

clippy_lints/src/utils/inspector.rs

+7-9
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
55
use rustc::lint::*;
66
use rustc::hir;
7-
use syntax::ast::{Attribute, MetaItemKind};
7+
use syntax::ast::Attribute;
8+
use syntax::attr;
89

910
/// **What it does:** Dumps every ast/hir node which has the `#[clippy_dump]` attribute
1011
///
@@ -128,10 +129,7 @@ impl LateLintPass for Pass {
128129
}
129130

130131
fn has_attr(attrs: &[Attribute]) -> bool {
131-
attrs.iter().any(|attr| match attr.node.value.node {
132-
MetaItemKind::Word(ref word) => word == "clippy_dump",
133-
_ => false,
134-
})
132+
attr::contains_name(attrs, "clippy_dump")
135133
}
136134

137135
fn print_decl(cx: &LateContext, decl: &hir::Decl) {
@@ -381,12 +379,12 @@ fn print_item(cx: &LateContext, item: &hir::Item) {
381379
}
382380
},
383381
hir::ItemDefaultImpl(_, ref trait_ref) => {
384-
let trait_did = cx.tcx.map.local_def_id(trait_ref.ref_id);
385-
println!("default impl for `{:?}`", cx.tcx.item_path_str(trait_did));
382+
let trait_did = cx.tcx.expect_def(trait_ref.ref_id).def_id();
383+
println!("default impl for `{}`", cx.tcx.item_path_str(trait_did));
386384
},
387385
hir::ItemImpl(_, _, _, Some(ref trait_ref), _, _) => {
388-
let trait_did = cx.tcx.map.local_def_id(trait_ref.ref_id);
389-
println!("impl of trait `{:?}`", cx.tcx.item_path_str(trait_did));
386+
let trait_did = cx.tcx.expect_def(trait_ref.ref_id).def_id();
387+
println!("impl of trait `{}`", cx.tcx.item_path_str(trait_did));
390388
},
391389
hir::ItemImpl(_, _, _, None, _, _) => {
392390
println!("impl");

clippy_lints/src/utils/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use std::env;
1414
use std::mem;
1515
use std::str::FromStr;
1616
use syntax::ast::{self, LitKind};
17+
use syntax::attr;
1718
use syntax::codemap::{ExpnFormat, ExpnInfo, MultiSpan, Span, DUMMY_SP};
1819
use syntax::errors::DiagnosticBuilder;
1920
use syntax::ptr::P;
@@ -761,3 +762,8 @@ pub fn is_refutable(cx: &LateContext, pat: &Pat) -> bool {
761762
}
762763
}
763764
}
765+
766+
/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d implementations have.
767+
pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
768+
attr::contains_name(attrs, "automatically_derived")
769+
}
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![feature(plugin)]
2+
#![plugin(clippy)]
3+
4+
#![deny(warnings)]
5+
#![allow(dead_code)]
6+
7+
struct Foo;
8+
9+
impl PartialEq for Foo {
10+
fn eq(&self, _: &Foo) -> bool { true }
11+
fn ne(&self, _: &Foo) -> bool { false }
12+
//~^ ERROR re-implementing `PartialEq::ne` is unnecessary
13+
}
14+
15+
fn main() {}

util/dogfood.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/bin/sh
22
rm -rf target*/*so
3-
cargo build --lib && cp -R target target_recur && cargo rustc -- -Zextra-plugins=clippy -Ltarget_recur/debug -Dclippy_pedantic -Dclippy || exit 1
3+
cargo build --lib && cp -R target target_recur && cargo rustc --lib -- -Zextra-plugins=clippy -Ltarget_recur/debug -Dclippy_pedantic -Dclippy || exit 1
44
rm -rf target_recur
55

0 commit comments

Comments
 (0)