-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Add lint for 'field_reassign_with_default` #568 #5911
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @Manishearth (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
r? @ebroto might take some time to get to this |
Just a heads-up, I'm half-through the review, should have the time to finish it later. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your pull request! I think this lint can be useful, especially for those not familiar with functional update syntax.
IMO this lint is trickier than it seems... I think the main issue I see with the current iteration is that as we don't recurse into subexpressions, with code like this:
let mut a: A = Default::default();
a.i = 42;
if true {
a.j = 21;
}
we would:
- Not catch the assignment to
j
- Worse, suggest making the binding immutable, suggesting code that does not compile.
To make this work, we would probably need a visitor that looks for assignments to the fields of the struct. But what if those assignments are inside a loop? What about function calls that take &mut
to one of the fields? We should avoid linting in those cases (see here for some examples of visitors).
I'm inclined to keep things simple and avoid recursing into subexpressions like we do now, but avoid suggesting an immutable binding. That way if there are other assignments we don't suggest code that does not compile, and if there are none rustc's unused_mut
will trigger after applying the suggestion.
What do y'all think @flip1995 @Manishearth ?
EDIT: To be clear, for this approach to work we should only take into account the assignments immediately following the call to Default::default
Thanks for finding the edge cases. I tried to reason about it originally and thought that that first one wasn't possible but my mental model was incorrect. There's a lot but I think I should be able to do another try with late lint pass and the offered suggestions. I'll get it through eventually since it's useful. |
75f2c69
to
daa5365
Compare
☔ The latest upstream changes (presumably #5952) made this pull request unmergeable. Please resolve the merge conflicts. |
Ping from triage @hegza. Did you have the time to address the review comments? If you are stuck on something we can try to help :) |
@ebroto On it. I made a pass on the trivial issues already and signed them off as resolved. It then took a while to assimilate the rest of what you said into a plan but I feel like I'm progressing and I'm at least currently having a good plan on what to tackle and in which order. I'll get in contact with you if I get stuck. In detail:
|
@ebroto now the only things missing are fields initialized as Defaul::default() and auto-apply. The auto-apply seems complicated because I'm not familiar with the concept of FRU. Can you clarify? Everything else should be done, but I'll leave it here until I can get a comment on the above two issues. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for taking the time to apply the suggestions!
Most of my new comments are related to style, but some of them require rethinking the lint a bit. As I said in the last review, I think this lint is trickier than it seems.
@hegza by FRU I mean "Functional Record Update", so the same thing we are trying to recommend in the suggestion. About the automatic fixes, see my new comment, we can leave them for a follow-up. |
There's progress (albeit slow; other responsibilities cluttering my weekends etc. the usual) but I'm still in the middle of some of the previous changes. I'll ping once I've decided on the next step for each review and recommendation. The main problem I'm working on is combining the lint with Thanks for another round of review, anyway :D |
Of course, no rush, this can wait :)
Don't hesitate to ping us regarding the refactoring in case you find a blocker. Again, thanks for sticking with this. I would be very happy to see this merged given the effort you've already put into it. |
5bfb948
to
679f755
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only thing missing are the remarks from the last round of review: #5911 (review)
After that I think we can merge this! :)
@ebroto I think the cases you refer to are already fixed but I hadn't signed them off. I wrote another test-case to verify that as well. I think we're done (maybe?) If you find more, let me know and I'll get back to it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the cases you refer to are already fixed
Indeed, we were just missing the test you added.
LGTM! Could you squash your commits into one? After that we can merge this!
- Implement `field_reassign_with_default` as a `LateLintPass` - Avoid triggering `default_trait_access` on a span already linted by `field_reassigned_with_default` - Merge `default_trait_access` and `field_reassign_with_default` into `Default` - Co-authored-by: Eduardo Broto <ebroto@tutanota.com> - Fixes rust-lang#568
Squashed @ebroto. |
@bors r+ Thanks for sticking with this during this really long review process ❤️ |
📌 Commit 7b203f3 has been approved by |
Add lint for 'field_reassign_with_default` #568 changelog: Add lint for field_reassign_with_default that checks if mutable object + field modification is used to edit a binding initialized with Default::default() instead of struct constructor. Fixes #568 Notes: - Checks for reassignment of one or more fields of a binding initialized with Default::default(). - Implemented using EarlyLintPass, might be future proofed better with LateLintPass. - Does not trigger if Default::default() is used via another type implementing Default. - This is a re-open of [PR#4761](#4761), but I couldn't figure out how to re-open that one so here's a new one with the requested changes :S
💔 Test failed - checks-action_test |
@bors retry |
☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test |
changelog: Add lint for field_reassign_with_default that checks if mutable object + field modification is used to edit a binding initialized with Default::default() instead of struct constructor.
Fixes #568
Notes: