Skip to content

Add assert_is_empty lint#17149

Open
joshka wants to merge 1 commit into
rust-lang:masterfrom
joshka:joshka/assert-is-empty
Open

Add assert_is_empty lint#17149
joshka wants to merge 1 commit into
rust-lang:masterfrom
joshka:joshka/assert-is-empty

Conversation

@joshka

@joshka joshka commented Jun 3, 2026

Copy link
Copy Markdown

changelog: new lint: [assert_is_empty]

fixes #17114

Adds a pedantic lint for assert! and debug_assert! calls that only check whether a supported value is empty. The lint suggests assert_eq!, assert_ne!, debug_assert_eq!, or debug_assert_ne! forms so failures print the unexpected value.

Rationale:

Boolean emptiness assertions only report that the predicate failed. In test failures, especially CI failures, that often leaves the developer without the collection contents needed to diagnose the problem. Comparing against an empty value gives the assertion machinery a value to print, and it also avoids hiding later content checks such as assert_eq!(items[0], "bar") behind a preceding assert!(!items.is_empty()) failure.

Supported suggestions currently cover strings, slices, arrays, and Vec. Other collection types are skipped when there is no compact empty-literal comparison or when the replacement assertion would not provide useful failure output.

Implementation notes:

  • Vec<T> suggestions use [] as [T; 0] so the empty operand carries enough type information for both assert_eq! and assert_ne!.
  • Arrays and borrowed vectors are compared through .as_slice() because direct comparison with [] does not compile for those receiver types.
  • Suggestions are only emitted when the replacement assertion can compare and print the value. Sequence element types must implement Debug and PartialEq.
  • Macro-expanded assertion conditions are skipped because rewriting generated spans can produce confusing or invalid suggestions.
  • Map-like collections are intentionally not covered yet. Comparing against HashMap::new() may be worth revisiting, but this PR keeps the first version to compact empty-literal comparisons.

New-lint checklist:

  • Followed lint naming conventions
  • Added passing UI tests, including committed .stderr and .fixed files
  • cargo test passes locally
  • Executed cargo dev update_lints
  • Added lint documentation
  • Run cargo dev fmt

Validation run locally:

  • cargo dev update_lints
  • cargo dev fmt
  • TESTNAME=assert_is_empty cargo uitest
  • cargo test --test dogfood
  • cargo test

@rustbot rustbot added the needs-fcp PRs that add, remove, or rename lints and need an FCP label Jun 3, 2026
@joshka joshka force-pushed the joshka/assert-is-empty branch from 036738a to d7911c9 Compare June 3, 2026 22:29
@rustbot

This comment has been minimized.

@joshka joshka force-pushed the joshka/assert-is-empty branch from d7911c9 to 4a8cdc6 Compare June 3, 2026 22:38
@joshka joshka marked this pull request as ready for review June 3, 2026 22:46
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Jun 3, 2026
@rustbot

rustbot commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @dswij (or someone else) some time within the next two weeks.

Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (S-waiting-on-review and S-waiting-on-author) stays updated, invoking these commands when appropriate:

  • @rustbot author: the review is finished, PR author should check the comments and take action accordingly
  • @rustbot review: the author is ready for a review, this PR will be queued again in the reviewer's queue
Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: 8 candidates
  • 8 candidates expanded to 8 candidates
  • Random selection from Jarcho, dswij, llogiq, samueltardieu

@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown

Lintcheck changes for 7763bb8

Lint Added Removed Changed
clippy::assert_is_empty 51 0 0

This comment will be updated if you push new changes

Comment thread tests/ui/assert_is_empty.stderr Outdated
@joshka joshka force-pushed the joshka/assert-is-empty branch from 4a8cdc6 to 3af5d85 Compare June 4, 2026 11:02
@DanielEScherzer

Copy link
Copy Markdown
Contributor

Just a note that it seems someone else has since had this idea at #17320
Looks like you properly checked for PartialEq and Debug that the other patch was missing :)

Warn when assert macros check collection emptiness in a way that hides
the collection contents on failure. The lint suggests assert_eq/assert_ne
forms for supported collections so failing tests print the unexpected
value.
@joshka joshka force-pushed the joshka/assert-is-empty branch from 97e93cb to 7763bb8 Compare July 10, 2026 08:01
@joshka

joshka commented Jul 10, 2026

Copy link
Copy Markdown
Author

@rustbot assign @llogiq
@rustbot ready

@rustbot rustbot assigned llogiq and unassigned dswij Jul 10, 2026
@joshka

joshka commented Jul 10, 2026

Copy link
Copy Markdown
Author

Following up on Daniel’s note above: I reviewed #17320 and left the fuller gap analysis here: #17320 (comment).

The useful implementation detail from that PR was the early ExprKind::If check before walking macro backtraces. I carried that over here in 7763bb81ba0e. assert! and debug_assert! expand to if, so this lets the lint skip non-assert-shaped expressions before doing the more expensive macro-backtrace work.

The main differences from this side are intentional:

  • This PR checks Debug and PartialEq before suggesting assert_eq! / assert_ne!, so the lint should not suggest replacements that fail to compile for element types that cannot be printed or compared.
  • Vec<T> suggestions use a typed empty array, for example:
assert_eq!(items, [] as [T; 0]);
assert_ne!(items, [] as [T; 0]);

That avoids type inference failures from a bare [].

  • This PR handles debug_assert!, borrowed vectors, mutable borrowed vectors, arrays, borrowed arrays, slices, String, and str.
  • Suggestions preserve custom assertion messages by editing the macro suffix and condition expression instead of replacing the whole macro call.
  • The UI coverage includes unsupported or unsafe suggestion cases, including missing Debug, missing PartialEq, both missing, map-like collections without a compact empty literal, and macro expansion cases.
  • The lint docs here spell out the CI/debugging failure mode and the common chained-assertion case where an emptiness assertion prevents a later contents assertion from running.
  • This PR intentionally skips macro-expanded assertion conditions/assertions. The duplicate PR instead emits help-only diagnostics for those cases. I think skipping is the better first-version behavior because macro-expanded diagnostics can point at code the user cannot fix at the call site, and changing the macro definition may not be correct for every caller.

One diagnostic wording difference that came up while comparing them: this PR now uses polarity-aware wording and explains why the replacement helps.

For a non-empty check, this PR reports:

error: used `assert!` to check that a value is not empty
  --> tests/ui/assert_is_empty.rs:9:5
   |
LL |     assert!(!vec.is_empty());
   |     ^^^^^^^^^^^^^^^^^^^^^^^^
   |
help: use `assert_ne!` to show the value on failure

The duplicate currently reports the same shape as:

error: used `assert!` with a non-empty collection check
  --> tests/ui/assert_is_empty.rs:9:5
   |
LL |     assert!(!v.is_empty());
   |     ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `assert_ne!(v, [])`

Both point in the same direction, but I think the wording here is clearer: the diagnostic names the actual state being checked, and the help text says that the replacement is useful because it shows the value on failure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-fcp PRs that add, remove, or rename lints and need an FCP S-waiting-on-review Status: Awaiting review from the assignee but also interested parties

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lint assertions on collection emptiness checks

6 participants