Now that we have rustfix integrated in our testsuite, we can use it to make sure that the suggestions we provide are valid rust code. This will also be useful once cargo fix --clippy is available to users.
This tracking issue is meant to give an overview of how many lints currently provide incorrect suggestions.
Below is the list of tests that include MachineApplicable but incorrect suggestions. For this issue to be closed, we need to add // run-rustfix to all of them and have the tests execute successfully.
If you want to help out with this, feel free to select one file that is not fixed and leave a comment below. Smaller files are most likely easier to fix.
// run-rustfix to the .rs file run cargo test && tests/ui/update-all-references.sh && cargo test. The tests for your file should fail and it should have generated a *.fixed filerustc tests/ui/<your_test_file>.fixed to see the exact compilation errortests/ui/assign_ops.rstests/ui/assign_ops2.rstests/ui/cmp_owned.rstests/ui/deref_addrof_double_trigger.rstests/ui/entry.rstests/ui/eq_op.rstests/ui/float_cmp.rstests/ui/float_cmp_const.rstests/ui/for_loop.rstests/ui/identity_conversion.rstests/ui/implicit_return.rstests/ui/inline_fn_without_body.rstests/ui/int_plus_one.rstests/ui/literals.rstests/ui/map_flatten.rstests/ui/mem_discriminant.rstests/ui/needless_borrow.rstests/ui/needless_borrowed_ref.rstests/ui/needless_collect.rstests/ui/needless_return.rstests/ui/non_copy_const.rstests/ui/op_ref.rs (https://github.com/rust-lang/rust-clippy/issues/2597)tests/ui/option_map_unit_fn.rstests/ui/or_fun_call.rstests/ui/outer_expn_data.rstests/ui/range_plus_minus_one.rstests/ui/redundant_closure_call.rstests/ui/redundant_pattern_matching.rstests/ui/rename.rstests/ui/renamed_builtin_attr.rstests/ui/redundant_static_lifetimes.rstests/ui/result_map_unit_fn.rs #4571tests/ui/short_circuit_statement.rstests/ui/strings.rstests/ui/toplevel_ref_arg.rs #4567tests/ui/unnecessary_clone.rstests/ui/unnecessary_operation.rstests/ui/wildcard_enum_match_arm.rs #4562tests/ui/useless_attribute.rsI'm currently going through the list, writing down why each test doesn't work with run-rustfix yet, and fixing the easy ones.
Could you share what you write down here, for lints which you don't get to fix, so that future contributors have an easier start?
@flip1995 Was already doing that, but I guess I can just edit my comment while I'm working through the list.
cfg_attr_rustfmt: Custom inner attributes are unstable. Let's disable the lint for inner attributes until #54726 stabilizescollapsible_if: unrelated cyclomatic_complexity warning that can be ignoredduration_subsec: Simply needed #![allow(dead_code)]excessive_precision: Fixed by #!allow(dead_code,unused_variables)explicit_write: Fixed by #![allow(unused_imports)]inconsistent_digit_grouping: Triggered unrelated clippy::excessive_precision lintinfallible_destructuring_match: Fixed by #![allow(dead_code, unreachable_code, unused_variables)]into_iter_on_ref: Triggered unrelated clippy::useless_vec lintlarge_digit_groups: Triggered clippy::excessive_precision lintmap_clone: Fixed by #![allow(clippy::iter_cloned_collect)]mem_replace: Suggestion causes import to be unused, fixed by #![allow(unused_imports)]precedence: Allow some unrelated lints, and change out-of-range 0b1111_1111i8 literalredundant_field_names: Allow dead code, and remove stabilized feature togglesreplace_consts: Fixed by #![allow(unused_variables)]starts_ends_with: Fixed by #![allow(unused_must_use)]types: Fixed by #![allow(dead_code, unused_variables)]unit_arg: Fixed by #[allow(unused_must_use)]unnecessary_fold: Fixed by adding type annotations and adding #![allow(dead_code)]bytecount: Suggestions use bytecount crate which probably isn't importedcast: Only cast-lossless is machine-applicable, others like cast_precision_loss aren't. Split the tests?decimal_literal_representation: 4_042_322_160 is out of range for i32, but using 4_042_322_160_u32 leads to a suggestion of 0xF0F0_F0F0, without the _u32expect_fun_call: Excess ) (this suggestion), but fixing that leads to a borrowed value does not live long enough error herefn_to_numeric_cast: The suggestion changes the type (to usize in a function that returns i32)for_loop: Suggests invalid .... Also several other invalid suggestions that result in syntax errors or iterating over ()len_zero: The len_without_is_empty lint triggers because the test defines its own len() function. len_without_is_empty should probably not trigger here.literals: rustfix panics with error Cannot replace slice of data that was already replaced.matches: The suggestions don't seem to be applied (or update-references.sh isn't working)methods: This test does #![warn(clippy::all)] and then whitelists some, but several other lints are triggered that are not in the whitelist. This test needs to be rewritten to trigger less lints, or it should use a blacklist insteadneedless_bool: Needs #![allow(clippy::no_effect, path_statements, unused_must_use)], and some lint warnings don't have suggestions, such as this if-then-else expression will always return truereference: The test is designed to trigger new lints after applying the suggestions, so it can't use the current run-rustfix (unless you can specify that a line will trigger a lint after applying the suggestion)strings: clippy::string_add currently doesn't give suggestions in all cases yetunnecessary_operation: [42, 55][get_number() as usize]; gets replaced by [42, 55];get_number() as usize;, but that triggers the lint again to replace get_number() as usize; with get_number();use_self: See #3567 useless_asref: It replaces foo_rrrrmr((&&&&MoreRef).as_ref()) with foo_rrrrmr((&&&&MoreRef)), which triggers the unused_parens lint. The lint should probably remove those parenswhile_loop: This lint makes suggestions like while let Some(_x) = y { .. }, which aren't meant to be machine-applicable (run-rustfix literally places .. there, instead of the code block)That's the whole list! Some of these are tricky cases:
Suggestions that trigger another lint afterwards
Sometimes this is unavoidable. If it is somehow possible we should maybe set _all_ Clippy lints to warn/allow in the second pass, where the *.rustfix files are checked.
but what if a lint needs a new import, or removes the last usage of the import? Should the lint be able to add/remove imports
If that's the case, the lint shouldn't be MachineApplicable but MaybeIncorrect.
Just a note. If the .fixed file fails to compile due a Clippy warning, you can run
CLIPPY_TESTS=true cargo run --bin clippy-driver tests/ui/<test>.fixed
to see.
I have replaced the list at the top with one generated with the rustfix-coverage flag from compiletest-rs. There's quite a bit to do.
The problem with tests/ui/deref_addrof_double_trigger.rs is that it needs two passes of the test-and-fix cycle. I feel like we should just exclude it.
I'm working through these from the top-down. Currently on eq_op.
Ticking off some boxes early:
So _many_ of these issues seem to be "fixable tests and unfixable tests are mixed in the same file". For a rustfix test to work, the fixed test must compile with no clippy warnings, which means the test cannot _also_ contain tests which do not get fixed.
(Given that, this may be a much smaller problem than we imagined)
Posted https://github.com/rust-lang/rust-clippy/pull/4558, will make more progress tomorrow on the plane.
More in https://github.com/rust-lang/rust-clippy/pull/4575
With this and #4571 we have nine left to go!
I updated #4575 to just mark op_ref as MaybeIncorrect for now. We're done!
Awesome! thanks @Manishearth for finishing this up :tada:
Oh, as a next step, we could probably use the compiletest-rs rustfix coverage tracking to make sure all new MachineApplicable diagnostics have a test file. I'll file a new issue later today.
It would be nice if compiletest had a mode that didn't force you to split files into rustfixable and non-rustfixable, where it tries to fix the code and then rechecks the file, only looking for errors which aren't fixable. We can also check in the .fixed-stderr file in that case. This way we could run-rustfix by default.
Most helpful comment
@flip1995 Was already doing that, but I guess I can just edit my comment while I'm working through the list.
Fixing this myself (PR: #3658)
cfg_attr_rustfmt: Custom inner attributes are unstable. Let's disable the lint for inner attributes until #54726 stabilizescollapsible_if: unrelated cyclomatic_complexity warning that can be ignoredduration_subsec: Simply needed#![allow(dead_code)]excessive_precision: Fixed by#!allow(dead_code,unused_variables)explicit_write: Fixed by#![allow(unused_imports)]inconsistent_digit_grouping: Triggered unrelatedclippy::excessive_precisionlintinfallible_destructuring_match: Fixed by#![allow(dead_code, unreachable_code, unused_variables)]into_iter_on_ref: Triggered unrelatedclippy::useless_veclintlarge_digit_groups: Triggeredclippy::excessive_precisionlintmap_clone: Fixed by#![allow(clippy::iter_cloned_collect)]mem_replace: Suggestion causes import to be unused, fixed by#![allow(unused_imports)]precedence: Allow some unrelated lints, and change out-of-range0b1111_1111i8literalredundant_field_names: Allow dead code, and remove stabilized feature togglesreplace_consts: Fixed by#![allow(unused_variables)]starts_ends_with: Fixed by#![allow(unused_must_use)]types: Fixed by#![allow(dead_code, unused_variables)]unit_arg: Fixed by#[allow(unused_must_use)]unnecessary_fold: Fixed by adding type annotations and adding#![allow(dead_code)]Not yet fixed
bytecount: Suggestions usebytecountcrate which probably isn't importedcast: Onlycast-losslessis machine-applicable, others likecast_precision_lossaren't. Split the tests?decimal_literal_representation:4_042_322_160is out of range for i32, but using4_042_322_160_u32leads to a suggestion of0xF0F0_F0F0, without the_u32expect_fun_call: Excess)(this suggestion), but fixing that leads to aborrowed value does not live long enougherror herefn_to_numeric_cast: The suggestion changes the type (tousizein a function that returnsi32)for_loop: Suggests invalid.... Also several other invalid suggestions that result in syntax errors or iterating over()len_zero: Thelen_without_is_emptylint triggers because the test defines its ownlen()function.len_without_is_emptyshould probably not trigger here.literals: rustfix panics with errorCannot replace slice of data that was already replaced.matches: The suggestions don't seem to be applied (orupdate-references.shisn't working)methods: This test does#![warn(clippy::all)]and then whitelists some, but several other lints are triggered that are not in the whitelist. This test needs to be rewritten to trigger less lints, or it should use a blacklist insteadneedless_bool: Needs#![allow(clippy::no_effect, path_statements, unused_must_use)], and some lint warnings don't have suggestions, such asthis if-then-else expression will always return truereference: The test is designed to trigger new lints after applying the suggestions, so it can't use the currentrun-rustfix(unless you can specify that a line will trigger a lint after applying the suggestion)strings:clippy::string_addcurrently doesn't give suggestions in all cases yetunnecessary_operation:[42, 55][get_number() as usize];gets replaced by[42, 55];get_number() as usize;, but that triggers the lint again to replaceget_number() as usize;withget_number();use_self: See #3567useless_asref: It replacesfoo_rrrrmr((&&&&MoreRef).as_ref())withfoo_rrrrmr((&&&&MoreRef)), which triggers theunused_parenslint. The lint should probably remove those parenswhile_loop: This lint makes suggestions likewhile let Some(_x) = y { .. }, which aren't meant to be machine-applicable (run-rustfixliterally places..there, instead of the code block)Notes on the process
That's the whole list! Some of these are tricky cases: