Skip to content

Commit 322c1a0

Browse files
authored
Merge pull request #1210 from Manishearth/len_without_is_empty
Len without is empty
2 parents 9c736dc + b2de244 commit 322c1a0

File tree

4 files changed

+80
-36
lines changed

4 files changed

+80
-36
lines changed

CHANGELOG.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
All notable changes to this project will be documented in this file.
33

44
## 0.0.88 — ??
5-
* The following lints are not new but were missing from the [`clippy`] and [`clippy_pedantic`] groups: [`filter_next`], [`for_loop_over_option`], [`for_loop_over_result`], [`match_overlapping_arm`].
5+
* The following lints are not new but were only usable through the `clippy`
6+
lint groups: [`filter_next`], [`for_loop_over_option`],
7+
[`for_loop_over_result`] and [`match_overlapping_arm`]. You should now be
8+
able to `#[allow/deny]` them individually and they are available directly
9+
through [`cargo clippy`].
610

711
## 0.0.87 — 2016-08-31
812
* Rustup to *rustc 1.13.0-nightly (eac41469d 2016-08-30)*

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ name
8484
[items_after_statements](https://github.com/Manishearth/rust-clippy/wiki#items_after_statements) | allow | blocks where an item comes after a statement
8585
[iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended
8686
[iter_nth](https://github.com/Manishearth/rust-clippy/wiki#iter_nth) | warn | using `.iter().nth()` on a standard library type with O(1) element access
87-
[len_without_is_empty](https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty) | warn | traits and impls that have `.len()` but not `.is_empty()`
87+
[len_without_is_empty](https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty) | warn | traits or impls with a public `len` method but no corresponding `is_empty` method
8888
[len_zero](https://github.com/Manishearth/rust-clippy/wiki#len_zero) | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead
8989
[let_and_return](https://github.com/Manishearth/rust-clippy/wiki#let_and_return) | warn | creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block
9090
[let_unit_value](https://github.com/Manishearth/rust-clippy/wiki#let_unit_value) | warn | creating a let binding to a value of unit type, which usually can't be used afterwards

clippy_lints/src/len_zero.rs

+25-19
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ declare_lint! {
4242
/// **Example:**
4343
/// ```rust
4444
/// impl X {
45-
/// fn len(&self) -> usize { .. }
45+
/// pub fn len(&self) -> usize { .. }
4646
/// }
4747
/// ```
4848
declare_lint! {
4949
pub LEN_WITHOUT_IS_EMPTY,
5050
Warn,
51-
"traits and impls that have `.len()` but not `.is_empty()`"
51+
"traits or impls with a public `len` method but no corresponding `is_empty` method"
5252
}
5353

5454
#[derive(Copy,Clone)]
@@ -99,13 +99,12 @@ fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[TraitItem]) {
9999
}
100100

101101
if !trait_items.iter().any(|i| is_named_self(i, "is_empty")) {
102-
for i in trait_items {
103-
if is_named_self(i, "len") {
102+
if let Some(i) = trait_items.iter().find(|i| is_named_self(i, "len")) {
103+
if cx.access_levels.is_exported(i.id) {
104104
span_lint(cx,
105105
LEN_WITHOUT_IS_EMPTY,
106106
i.span,
107-
&format!("trait `{}` has a `.len(_: &Self)` method, but no `.is_empty(_: &Self)` method. \
108-
Consider adding one",
107+
&format!("trait `{}` has a `len` method but no `is_empty` method",
109108
item.name));
110109
}
111110
}
@@ -122,19 +121,26 @@ fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItem]) {
122121
}
123122
}
124123

125-
if !impl_items.iter().any(|i| is_named_self(i, "is_empty")) {
126-
for i in impl_items {
127-
if is_named_self(i, "len") {
128-
let ty = cx.tcx.node_id_to_type(item.id);
129-
130-
span_lint(cx,
131-
LEN_WITHOUT_IS_EMPTY,
132-
i.span,
133-
&format!("item `{}` has a `.len(_: &Self)` method, but no `.is_empty(_: &Self)` method. \
134-
Consider adding one",
135-
ty));
136-
return;
137-
}
124+
let is_empty = if let Some(is_empty) = impl_items.iter().find(|i| is_named_self(i, "is_empty")) {
125+
if cx.access_levels.is_exported(is_empty.id) {
126+
return;
127+
} else {
128+
"a private"
129+
}
130+
} else {
131+
"no corresponding"
132+
};
133+
134+
if let Some(i) = impl_items.iter().find(|i| is_named_self(i, "len")) {
135+
if cx.access_levels.is_exported(i.id) {
136+
let ty = cx.tcx.node_id_to_type(item.id);
137+
138+
span_lint(cx,
139+
LEN_WITHOUT_IS_EMPTY,
140+
i.span,
141+
&format!("item `{}` has a public `len` method but {} `is_empty` method",
142+
ty,
143+
is_empty));
138144
}
139145
}
140146
}

tests/compile-fail/len_zero.rs

+49-15
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,45 @@
11
#![feature(plugin)]
22
#![plugin(clippy)]
33

4+
#![deny(len_without_is_empty, len_zero)]
5+
#![allow(dead_code, unused)]
6+
7+
pub struct PubOne;
8+
9+
impl PubOne {
10+
pub fn len(self: &Self) -> isize { //~ERROR item `PubOne` has a public `len` method but no corresponding `is_empty`
11+
1
12+
}
13+
}
14+
15+
struct NotPubOne;
16+
17+
impl NotPubOne {
18+
pub fn len(self: &Self) -> isize { // no error, len is pub but `NotPubOne` is not exported anyway
19+
1
20+
}
21+
}
22+
423
struct One;
524

6-
#[deny(len_without_is_empty)]
725
impl One {
8-
fn len(self: &Self) -> isize { //~ERROR item `One` has a `.len(_: &Self)`
26+
fn len(self: &Self) -> isize { // no error, len is private, see #1085
927
1
1028
}
1129
}
1230

13-
#[deny(len_without_is_empty)]
31+
pub trait PubTraitsToo {
32+
fn len(self: &Self) -> isize; //~ERROR trait `PubTraitsToo` has a `len` method but no `is_empty`
33+
}
34+
35+
impl PubTraitsToo for One {
36+
fn len(self: &Self) -> isize {
37+
0
38+
}
39+
}
40+
1441
trait TraitsToo {
15-
fn len(self: &Self) -> isize; //~ERROR trait `TraitsToo` has a `.len(_:
42+
fn len(self: &Self) -> isize; // no error, len is private, see #1085
1643
}
1744

1845
impl TraitsToo for One {
@@ -21,11 +48,22 @@ impl TraitsToo for One {
2148
}
2249
}
2350

24-
struct HasIsEmpty;
51+
struct HasPrivateIsEmpty;
52+
53+
impl HasPrivateIsEmpty {
54+
pub fn len(self: &Self) -> isize {
55+
1
56+
}
57+
58+
fn is_empty(self: &Self) -> bool {
59+
false
60+
}
61+
}
62+
63+
pub struct HasIsEmpty;
2564

26-
#[deny(len_without_is_empty)]
2765
impl HasIsEmpty {
28-
fn len(self: &Self) -> isize {
66+
pub fn len(self: &Self) -> isize { //~ERROR item `HasIsEmpty` has a public `len` method but a private `is_empty`
2967
1
3068
}
3169

@@ -36,8 +74,7 @@ impl HasIsEmpty {
3674

3775
struct Wither;
3876

39-
#[deny(len_without_is_empty)]
40-
trait WithIsEmpty {
77+
pub trait WithIsEmpty {
4178
fn len(self: &Self) -> isize;
4279
fn is_empty(self: &Self) -> bool;
4380
}
@@ -52,21 +89,18 @@ impl WithIsEmpty for Wither {
5289
}
5390
}
5491

55-
struct HasWrongIsEmpty;
92+
pub struct HasWrongIsEmpty;
5693

57-
#[deny(len_without_is_empty)]
5894
impl HasWrongIsEmpty {
59-
fn len(self: &Self) -> isize { //~ERROR item `HasWrongIsEmpty` has a `.len(_: &Self)`
95+
pub fn len(self: &Self) -> isize { //~ERROR item `HasWrongIsEmpty` has a public `len` method but no corresponding `is_empty`
6096
1
6197
}
6298

63-
#[allow(dead_code, unused)]
64-
fn is_empty(self: &Self, x : u32) -> bool {
99+
pub fn is_empty(self: &Self, x : u32) -> bool {
65100
false
66101
}
67102
}
68103

69-
#[deny(len_zero)]
70104
fn main() {
71105
let x = [1, 2];
72106
if x.len() == 0 {

0 commit comments

Comments
 (0)