Skip to content

expect(len_without_is_empty) can trigger unfulfilled_lint_expectations when not enabled #14597

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
eric-seppanen opened this issue Apr 12, 2025 · 5 comments · Fixed by #14604
Closed
Assignees
Labels
C-bug Category: Clippy is not doing the correct thing

Comments

@eric-seppanen
Copy link

Summary

Most lints are silent when using #[expect(some_lint)] if that lint isn't enabled.

However, len_without_is_empty seems to be different. #[expect(clippy::len_without_is_empty)] will trigger a warning if I run clippy with that lint disabled. Even if the affected code does trigger that lint-- it's just seems unhappy about being disabled.

Reproducer

This code produces no errors when I run cargo clippy:

pub struct Empty;

impl Empty {
    #[expect(clippy::len_without_is_empty)]
    pub fn len(&self) -> usize {
        0
    }
}

#[expect(clippy::bool_comparison)]
pub fn silly(x: bool) {
    if x == true {
        println!("true");
    }
}

But if I run cargo clippy -- -Aclippy::all I get an unexpected warning:

warning: this lint expectation is unfulfilled
 --> src/lib.rs:4:14
  |
4 |     #[expect(clippy::len_without_is_empty)]
  |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unfulfilled_lint_expectations)]` on by default

This seems strange: there are two lints being expected here, but only one of them complains when not enabled. As far as I can tell most clippy lints are well-behaved in this condition, and don't trigger warnings when expected but disabled.

Running clippy with -Aclippy::all doesn't seem like a very useful thing to do, and I agree. The thing that I do actually want to do is something like this:

cargo clippy --fix -- -Aclippy::all -Wclippy::useless_nonzero_new_unchecked

... so that I can capture fixes for that particular lint into a standalone commit. And it seems surprising when I get warnings when some unrelated lint was "unfulfilled" in a spurious way.

Version

cargo 1.86.0 (adf9b6ad1 2025-02-28)
release: 1.86.0
commit-hash: adf9b6ad14cfa10ff680d5806741a144f7163698
commit-date: 2025-02-28
host: x86_64-unknown-linux-gnu
libgit2: 1.9.0 (sys:0.20.0 vendored)
libcurl: 8.12.0-DEV (sys:0.4.79+curl-8.12.0 vendored ssl:OpenSSL/1.1.1w)
ssl: OpenSSL 1.1.1w  11 Sep 2023
os: Ubuntu 24.4.0 (noble) [64-bit]

This happens with every stable compiler since 1.81.0 when the `#[expect]` attribute was stabilized.

Additional Labels

No response

@eric-seppanen eric-seppanen added the C-bug Category: Clippy is not doing the correct thing label Apr 12, 2025
@samueltardieu
Copy link
Contributor

What you are seeing is likely a consequence of the second change in #6853:

len_without_is_empty will now consider #[allow] on both the len method, and the type definition

In your case, the lint is allowed at the place of the type definition, so it won't trigger. As a workaround, you may want to apply #[deny(clippy::len_without_is_empty)] to the pub struct Empty; declaration.

@eric-seppanen
Copy link
Author

@samueltardieu I'm not trying to deny the lint, I'm trying to expect it, meaning I want the lint to be ignored at this location.

Moving the expect to the struct definition does not work: the len_without_is_empty lint can be allowed there but expect does not work. Maybe that's a separate bug? I can file another issue if that would help.

@samueltardieu
Copy link
Contributor

@samueltardieu I'm not trying to deny the lint, I'm trying to expect it, meaning I want the lint to be ignored at this location.

I understand this. My proposal is only a workaround, as if the lint is allowed on the type (which it is because of -Aclippy::all) or on the len() definition (which it isn't because of the #[expected]), then it will not trigger and the #[expected] will fail, as you noticed. By removing the allow on the type, using #[deny] on it, the #[expected] will then trigger on the function.

@samueltardieu
Copy link
Contributor

Moving the expect to the struct definition does not work

Yes, the lint is raised on the function definition, which is not located under the struct definition, so it is expected (in the current state of things) that it won't work.

@samueltardieu
Copy link
Contributor

I've opened a thread on Zulip to discuss the various possibilities.

@samueltardieu samueltardieu self-assigned this Apr 13, 2025
github-merge-queue bot pushed a commit that referenced this issue Apr 13, 2025
`clippy::len_without_is_empty` can be allowed at the type declaration
site, and this will prevent the lint from triggering even though the
lint is shown on the `len()` method definition.

This allows the lint to be expected even though it is allowed at the
type declaration site.

changelog: [`len_without_is_empty`]: the lint can now be `#[expect]`ed
on the `len()` method even when it is `#[allow]`ed on the definining
type.

Fixes #14597
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: Clippy is not doing the correct thing
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants