len_without_is_empty false positive #1740
This commit is contained in:
parent
73d87d966d
commit
ec79970771
@ -2,6 +2,7 @@ use rustc::lint::*;
|
|||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::ty;
|
use rustc::ty;
|
||||||
use rustc::hir::*;
|
use rustc::hir::*;
|
||||||
|
use std::collections::HashSet;
|
||||||
use syntax::ast::{Lit, LitKind, Name};
|
use syntax::ast::{Lit, LitKind, Name};
|
||||||
use syntax::codemap::{Span, Spanned};
|
use syntax::codemap::{Span, Spanned};
|
||||||
use utils::{get_item_name, in_macro, snippet, span_lint, span_lint_and_sugg, walk_ptrs_ty};
|
use utils::{get_item_name, in_macro, snippet, span_lint, span_lint_and_sugg, walk_ptrs_ty};
|
||||||
@ -88,7 +89,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LenZero {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[TraitItemRef]) {
|
fn check_trait_items(cx: &LateContext, visited_trait: &Item, trait_items: &[TraitItemRef]) {
|
||||||
fn is_named_self(cx: &LateContext, item: &TraitItemRef, name: &str) -> bool {
|
fn is_named_self(cx: &LateContext, item: &TraitItemRef, name: &str) -> bool {
|
||||||
item.name == name &&
|
item.name == name &&
|
||||||
if let AssociatedItemKind::Method { has_self } = item.kind {
|
if let AssociatedItemKind::Method { has_self } = item.kind {
|
||||||
@ -102,18 +103,52 @@ fn check_trait_items(cx: &LateContext, item: &Item, trait_items: &[TraitItemRef]
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !trait_items.iter().any(|i| is_named_self(cx, i, "is_empty")) {
|
// fill the set with current and super traits
|
||||||
if let Some(i) = trait_items.iter().find(|i| is_named_self(cx, i, "len")) {
|
fn fill_trait_set<'a, 'b: 'a>(traitt: &'b Item, set: &'a mut HashSet<&'b Item>, cx: &'b LateContext) {
|
||||||
if cx.access_levels.is_exported(i.id.node_id) {
|
if set.insert(traitt) {
|
||||||
span_lint(
|
if let ItemTrait(.., ref ty_param_bounds, _) = traitt.node {
|
||||||
cx,
|
for ty_param_bound in ty_param_bounds {
|
||||||
LEN_WITHOUT_IS_EMPTY,
|
if let TraitTyParamBound(ref poly_trait_ref, _) = *ty_param_bound {
|
||||||
item.span,
|
let super_trait_node_id = cx.tcx
|
||||||
&format!("trait `{}` has a `len` method but no `is_empty` method", item.name),
|
.hir
|
||||||
);
|
.as_local_node_id(poly_trait_ref.trait_ref.path.def.def_id())
|
||||||
|
.expect("the DefId is local, the NodeId should be available");
|
||||||
|
let super_trait = cx.tcx.hir.expect_item(super_trait_node_id);
|
||||||
|
fill_trait_set(super_trait, set, cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cx.access_levels.is_exported(visited_trait.id) &&
|
||||||
|
trait_items
|
||||||
|
.iter()
|
||||||
|
.any(|i| is_named_self(cx, i, "len"))
|
||||||
|
{
|
||||||
|
let mut current_and_super_traits = HashSet::new();
|
||||||
|
fill_trait_set(visited_trait, &mut current_and_super_traits, cx);
|
||||||
|
|
||||||
|
let is_empty_method_found = current_and_super_traits
|
||||||
|
.iter()
|
||||||
|
.flat_map(|i| match i.node {
|
||||||
|
ItemTrait(.., ref trait_items) => trait_items.iter(),
|
||||||
|
_ => bug!("should only handle traits"),
|
||||||
|
})
|
||||||
|
.any(|i| is_named_self(cx, i, "is_empty"));
|
||||||
|
|
||||||
|
if !is_empty_method_found {
|
||||||
|
span_lint(
|
||||||
|
cx,
|
||||||
|
LEN_WITHOUT_IS_EMPTY,
|
||||||
|
visited_trait.span,
|
||||||
|
&format!(
|
||||||
|
"trait `{}` has a `len` method but no (possibly inherited) `is_empty` method",
|
||||||
|
visited_trait.name
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItemRef]) {
|
fn check_impl_items(cx: &LateContext, item: &Item, impl_items: &[ImplItemRef]) {
|
||||||
|
@ -125,6 +125,16 @@ impl HasWrongIsEmpty {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Empty {
|
||||||
|
fn is_empty(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait InheritingEmpty: Empty { //must not trigger LEN_WITHOUT_IS_EMPTY
|
||||||
|
fn len(&self) -> isize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = [1, 2];
|
let x = [1, 2];
|
||||||
if x.len() == 0 {
|
if x.len() == 0 {
|
||||||
|
@ -10,7 +10,7 @@ error: item `PubOne` has a public `len` method but no corresponding `is_empty` m
|
|||||||
|
|
|
|
||||||
= note: `-D len-without-is-empty` implied by `-D warnings`
|
= note: `-D len-without-is-empty` implied by `-D warnings`
|
||||||
|
|
||||||
error: trait `PubTraitsToo` has a `len` method but no `is_empty` method
|
error: trait `PubTraitsToo` has a `len` method but no (possibly inherited) `is_empty` method
|
||||||
--> $DIR/len_zero.rs:55:1
|
--> $DIR/len_zero.rs:55:1
|
||||||
|
|
|
|
||||||
55 | / pub trait PubTraitsToo {
|
55 | / pub trait PubTraitsToo {
|
||||||
@ -43,47 +43,47 @@ error: item `HasWrongIsEmpty` has a public `len` method but no corresponding `is
|
|||||||
| |_^
|
| |_^
|
||||||
|
|
||||||
error: length comparison to zero
|
error: length comparison to zero
|
||||||
--> $DIR/len_zero.rs:130:8
|
--> $DIR/len_zero.rs:140:8
|
||||||
|
|
|
|
||||||
130 | if x.len() == 0 {
|
140 | if x.len() == 0 {
|
||||||
| ^^^^^^^^^^^^ help: using `is_empty` is more concise: `x.is_empty()`
|
| ^^^^^^^^^^^^ help: using `is_empty` is more concise: `x.is_empty()`
|
||||||
|
|
|
|
||||||
= note: `-D len-zero` implied by `-D warnings`
|
= note: `-D len-zero` implied by `-D warnings`
|
||||||
|
|
||||||
error: length comparison to zero
|
error: length comparison to zero
|
||||||
--> $DIR/len_zero.rs:134:8
|
--> $DIR/len_zero.rs:144:8
|
||||||
|
|
|
|
||||||
134 | if "".len() == 0 {
|
144 | if "".len() == 0 {
|
||||||
| ^^^^^^^^^^^^^ help: using `is_empty` is more concise: `"".is_empty()`
|
| ^^^^^^^^^^^^^ help: using `is_empty` is more concise: `"".is_empty()`
|
||||||
|
|
||||||
error: length comparison to zero
|
error: length comparison to zero
|
||||||
--> $DIR/len_zero.rs:148:8
|
--> $DIR/len_zero.rs:158:8
|
||||||
|
|
|
|
||||||
148 | if has_is_empty.len() == 0 {
|
158 | if has_is_empty.len() == 0 {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `has_is_empty.is_empty()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `has_is_empty.is_empty()`
|
||||||
|
|
||||||
error: length comparison to zero
|
error: length comparison to zero
|
||||||
--> $DIR/len_zero.rs:151:8
|
--> $DIR/len_zero.rs:161:8
|
||||||
|
|
|
|
||||||
151 | if has_is_empty.len() != 0 {
|
161 | if has_is_empty.len() != 0 {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `!has_is_empty.is_empty()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `!has_is_empty.is_empty()`
|
||||||
|
|
||||||
error: length comparison to zero
|
error: length comparison to zero
|
||||||
--> $DIR/len_zero.rs:154:8
|
--> $DIR/len_zero.rs:164:8
|
||||||
|
|
|
|
||||||
154 | if has_is_empty.len() > 0 {
|
164 | if has_is_empty.len() > 0 {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `!has_is_empty.is_empty()`
|
| ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `!has_is_empty.is_empty()`
|
||||||
|
|
||||||
error: length comparison to zero
|
error: length comparison to zero
|
||||||
--> $DIR/len_zero.rs:160:8
|
--> $DIR/len_zero.rs:170:8
|
||||||
|
|
|
|
||||||
160 | if with_is_empty.len() == 0 {
|
170 | if with_is_empty.len() == 0 {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `with_is_empty.is_empty()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `with_is_empty.is_empty()`
|
||||||
|
|
||||||
error: length comparison to zero
|
error: length comparison to zero
|
||||||
--> $DIR/len_zero.rs:172:8
|
--> $DIR/len_zero.rs:182:8
|
||||||
|
|
|
|
||||||
172 | if b.len() != 0 {
|
182 | if b.len() != 0 {
|
||||||
| ^^^^^^^^^^^^ help: using `is_empty` is more concise: `!b.is_empty()`
|
| ^^^^^^^^^^^^ help: using `is_empty` is more concise: `!b.is_empty()`
|
||||||
|
|
||||||
error: aborting due to 11 previous errors
|
error: aborting due to 11 previous errors
|
||||||
|
Loading…
x
Reference in New Issue
Block a user