rust/tests/ui/len_without_is_empty.rs
ksaleem 2fd94a4e01 prevents len_without_is_empty from yielding positive when len takes
more than just `&self` in non-standard implementations.

changelog: Fix [`len_without_is_empty`] false positive when len has a
non-standard method signature

Fixes #9520
2023-01-29 17:35:36 -05:00

332 lines
5.8 KiB
Rust

#![warn(clippy::len_without_is_empty)]
#![allow(dead_code, unused)]
pub struct PubOne;
impl PubOne {
pub fn len(&self) -> isize {
1
}
}
impl PubOne {
// A second impl for this struct -- the error span shouldn't mention this.
pub fn irrelevant(&self) -> bool {
false
}
}
// Identical to `PubOne`, but with an `allow` attribute on the impl complaining `len`.
pub struct PubAllowed;
#[allow(clippy::len_without_is_empty)]
impl PubAllowed {
pub fn len(&self) -> isize {
1
}
}
// No `allow` attribute on this impl block, but that doesn't matter -- we only require one on the
// impl containing `len`.
impl PubAllowed {
pub fn irrelevant(&self) -> bool {
false
}
}
pub struct PubAllowedFn;
impl PubAllowedFn {
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> isize {
1
}
}
#[allow(clippy::len_without_is_empty)]
pub struct PubAllowedStruct;
impl PubAllowedStruct {
pub fn len(&self) -> isize {
1
}
}
pub trait PubTraitsToo {
fn len(&self) -> isize;
}
impl PubTraitsToo for One {
fn len(&self) -> isize {
0
}
}
pub struct HasIsEmpty;
impl HasIsEmpty {
pub fn len(&self) -> isize {
1
}
fn is_empty(&self) -> bool {
false
}
}
pub struct HasWrongIsEmpty;
impl HasWrongIsEmpty {
pub fn len(&self) -> isize {
1
}
pub fn is_empty(&self, x: u32) -> bool {
false
}
}
pub struct MismatchedSelf;
impl MismatchedSelf {
pub fn len(self) -> isize {
1
}
pub fn is_empty(&self) -> bool {
false
}
}
struct NotPubOne;
impl NotPubOne {
pub fn len(&self) -> isize {
// No error; `len` is pub but `NotPubOne` is not exported anyway.
1
}
}
struct One;
impl One {
fn len(&self) -> isize {
// No error; `len` is private; see issue #1085.
1
}
}
trait TraitsToo {
fn len(&self) -> isize;
// No error; `len` is private; see issue #1085.
}
impl TraitsToo for One {
fn len(&self) -> isize {
0
}
}
struct HasPrivateIsEmpty;
impl HasPrivateIsEmpty {
pub fn len(&self) -> isize {
1
}
fn is_empty(&self) -> bool {
false
}
}
struct Wither;
pub trait WithIsEmpty {
fn len(&self) -> isize;
fn is_empty(&self) -> bool;
}
impl WithIsEmpty for Wither {
fn len(&self) -> isize {
1
}
fn is_empty(&self) -> bool {
false
}
}
pub trait Empty {
fn is_empty(&self) -> bool;
}
pub trait InheritingEmpty: Empty {
// Must not trigger `LEN_WITHOUT_IS_EMPTY`.
fn len(&self) -> isize;
}
// This used to ICE.
pub trait Foo: Sized {}
pub trait DependsOnFoo: Foo {
fn len(&mut self) -> usize;
}
// issue #1562
pub struct MultipleImpls;
impl MultipleImpls {
pub fn len(&self) -> usize {
1
}
}
impl MultipleImpls {
pub fn is_empty(&self) -> bool {
false
}
}
// issue #6958
pub struct OptionalLen;
impl OptionalLen {
pub fn len(&self) -> Option<usize> {
Some(0)
}
pub fn is_empty(&self) -> Option<bool> {
Some(true)
}
}
pub struct OptionalLen2;
impl OptionalLen2 {
pub fn len(&self) -> Option<usize> {
Some(0)
}
pub fn is_empty(&self) -> bool {
true
}
}
pub struct OptionalLen3;
impl OptionalLen3 {
pub fn len(&self) -> usize {
0
}
// should lint, len is not an option
pub fn is_empty(&self) -> Option<bool> {
None
}
}
pub struct ResultLen;
impl ResultLen {
pub fn len(&self) -> Result<usize, ()> {
Ok(0)
}
// Differing result types
pub fn is_empty(&self) -> Option<bool> {
Some(true)
}
}
pub struct ResultLen2;
impl ResultLen2 {
pub fn len(&self) -> Result<usize, ()> {
Ok(0)
}
pub fn is_empty(&self) -> Result<bool, ()> {
Ok(true)
}
}
pub struct ResultLen3;
impl ResultLen3 {
pub fn len(&self) -> Result<usize, ()> {
Ok(0)
}
// Non-fallible result is ok.
pub fn is_empty(&self) -> bool {
true
}
}
pub struct OddLenSig;
impl OddLenSig {
// don't lint
pub fn len(&self) -> bool {
true
}
}
// issue #6958
pub struct AsyncLen;
impl AsyncLen {
async fn async_task(&self) -> bool {
true
}
pub async fn len(&self) -> usize {
usize::from(!self.async_task().await)
}
pub async fn is_empty(&self) -> bool {
self.len().await == 0
}
}
// issue #9520
pub struct NonStandardLenAndIsEmptySignature;
impl NonStandardLenAndIsEmptySignature {
// don't lint
pub fn len(&self, something: usize) -> usize {
something
}
pub fn is_empty(&self, something: usize) -> bool {
something == 0
}
}
// test case for #9520 with generics in the function signature
pub trait TestResource {
type NonStandardSignatureWithGenerics: Copy;
fn lookup_content(&self, item: Self::NonStandardSignatureWithGenerics) -> Result<Option<&[u8]>, String>;
}
pub struct NonStandardSignatureWithGenerics(u32);
impl NonStandardSignatureWithGenerics {
pub fn is_empty<T, U>(self, resource: &T) -> bool
where
T: TestResource<NonStandardSignatureWithGenerics = U>,
U: Copy + From<NonStandardSignatureWithGenerics>,
{
if let Ok(Some(content)) = resource.lookup_content(self.into()) {
content.is_empty()
} else {
true
}
}
// test case for #9520 with generics in the function signature
pub fn len<T, U>(self, resource: &T) -> usize
where
T: TestResource<NonStandardSignatureWithGenerics = U>,
U: Copy + From<NonStandardSignatureWithGenerics>,
{
if let Ok(Some(content)) = resource.lookup_content(self.into()) {
content.len()
} else {
0_usize
}
}
}
fn main() {}