Skip to content
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 manual_option_folding #11581

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

sjwang05
Copy link
Contributor

Closes #10646

This lint checks for panicking unwrap methods (unwrap, unwrap_unchecked, expect) used after get_or_insert_with.

changelog: new lint: [manual_option_folding]

@rustbot
Copy link
Collaborator

rustbot commented Sep 28, 2023

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @giraffate (or someone else) soon.

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

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Sep 28, 2023
@bors
Copy link
Contributor

bors commented Sep 29, 2023

☔ The latest upstream changes (presumably #11527) made this pull request unmergeable. Please resolve the merge conflicts.

@sjwang05 sjwang05 force-pushed the manual-option-folding branch from 6af6808 to 93f2de3 Compare September 29, 2023 03:31
@bors
Copy link
Contributor

bors commented Nov 14, 2023

☔ The latest upstream changes (presumably #11791) made this pull request unmergeable. Please resolve the merge conflicts.

@sjwang05 sjwang05 force-pushed the manual-option-folding branch from 3014bcf to 486cac5 Compare November 29, 2023 03:10
@bors
Copy link
Contributor

bors commented Dec 1, 2023

☔ The latest upstream changes (presumably #11597) made this pull request unmergeable. Please resolve the merge conflicts.

@xFrednet
Copy link
Member

Hey @sjwang05, sorry for the long wait. @giraffate is currently sadly busy and it went by unnoticed 🙈

Are you still interested in continuing this PR?

r? @xFrednet

@rustbot rustbot assigned xFrednet and unassigned giraffate Mar 31, 2024
@xFrednet xFrednet added S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties labels Apr 6, 2024
@xFrednet
Copy link
Member

Sorry, I totally forgot about this PR, since it wasn't in my inbox anymore 🙈 I'll add it to my todo list. You'll get a review next week!

Copy link
Member

@xFrednet xFrednet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, sorry for the long delay, just commenting r? @xFrednet didn't add it to my inbox 🙈

Anyways, the code is well written. There are several edge cases that need to be considered and might sadly not be solvable with this structure. I left some hints how this can be addressed. If you have any questions, please reach out!


fn main() {
let mut opt: Option<i32> = Some(42);
opt.get_or_insert_with(|| 21);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_or_insert returns &mut T. The lint has to check, that this value is not used. It would also be good to have tests for this

self.get_call = Some(expr);
self.recv = Some(recv);
self.get_method_name = Some(path.ident.name);
} else if let Some(get_call) = self.get_call.take()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This take is only executed on method expressions that fulfill the prerequisites at the beginning of this function.

This means that any number of expressions could between this and the previous insert. This can sadly lead to false positives, as in this example:

fn magic(condition: bool) -> u32 {
    let mut option = None;
    if condition {
        option.insert(19);
    }
    option.unwrap()
}

I think the best solution would be to check for block expressions and then iterate over the statements using a window of 2. That would only catch consequitve option.insert & option.unwrap things, but anything else would be way harder to implement and could result in false positives. Maybe you can take a look at [clippy::vec_init_then_push] here: clippy_lints/src/vec_init_then_push.rs. It's definitly a more complicated implementation, but that would be the best way AFAIK.

&& let ty = cx.typeck_results().expr_ty(recv).peel_refs()
&& is_type_diagnostic_item(cx, ty, sym::Option)
{
if path.ident.name == sym!(get_or_insert)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also catch usages of insert(), which has been added in Rust 1.53. We have some docs for how you can check for the specified MSRV: https://doc.rust-lang.org/clippy/development/adding_lints.html#specifying-the-lints-minimum-supported-rust-version-msrv

@xFrednet
Copy link
Member

Hey @sjwang05, this is a ping from triage, since there hasn't been any activity in some time. Are you still planning to continue this implementation?

If you have any questions, you're always welcome to ask them in this PR or on Zulip.

@rustbot author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

get_or_insert_with followed by unwrap can be replaced by unwrap_or_else
5 participants