-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New lint hashset_insert_after_contains
#11296
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
Conversation
r? @Manishearth (rustbot has picked a reviewer for you, use r? to override) |
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.
Pretty good for a first lint, thanks!
Thank you for the review, @Centri3 ! The code is looking way simpler with your suggestions :) Could you please take a look again and let me know what you think? The changes are in the commit |
r? @Centri3 you've already reviewed most of this 😄 |
kind: ExprKind::AddrOf(_, _, value), | ||
span: value_span, | ||
.. | ||
}, |
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.
This doesn't account for if it's not a reference. Of course, contains
takes a reference but it's free to be x
or something if x
is &Q
. I'd say just call peel_borrows
here and also do so for insert_expr.value
.
) = expr.kind | ||
{ | ||
let receiver_ty = cx.typeck_results().expr_ty(receiver); | ||
if value_span.ctxt() == expr.span.ctxt() |
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.
If the first argument and the call itself are both from the same expansion, this won't catch it. I'd just recommend calling from_expansion
on value_span
since that'll also check expr
.
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.
Let's see if I understood the changes that I need to apply here:
- Remove the
if value_span.ctxt() == expr.span.ctxt()
comparison. - Check if
value_span
is not from an expansion. If it is from an expasion, we will not lint - Check if
value_span
is nto from external_macro. If it is from an external macro, we will not lint.
Is it correct?
Hey @Centri3 ! I think I have addressed almost everything from you comments.
But I could not understand your comment about Thanks! :) |
The issue with However, I think ignoring all expansions isn't the right way to go about this; if it happens to expand to code that references a local, and also inserts into it, then it was likely intentionally done (if the local isn't also from an expansion, of course). So if it's not external, it should still lint. |
|
||
impl<'tcx> LateLintPass<'tcx> for HashsetInsertAfterContains { | ||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { | ||
if !expr.span.from_expansion() |
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.
This probably also needs an is_from_proc_macro
check right before emitting
span: Span, | ||
} | ||
fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<ContainsExpr<'tcx>> { | ||
let expr = peel_hir_expr_while(expr, |e| match e.kind { |
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.
This could be an if let
.
&& find_insert_calls(cx, &contains_expr, then_expr) { | ||
span_lint_and_then( |
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.
Very nitpicky, but:
&& find_insert_calls(cx, &contains_expr, then_expr) { | |
span_lint_and_then( | |
&& find_insert_calls(cx, &contains_expr, then_expr) | |
{ | |
span_lint_and_then( |
fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<InsertExpr<'tcx>> { | ||
if let ExprKind::MethodCall(path, receiver, [value], _) = expr.kind { | ||
let value = value.peel_borrows(); | ||
let value = peel_hir_expr_while(value, |e| match e.kind { |
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.
Same here
☔ The latest upstream changes (presumably #11373) made this pull request unmergeable. Please resolve the merge conflicts. |
Hey @Centri3 hello! Sorry for that long delay, but I think I will not be able to finish the PR 😬 |
No worries about it! I'll close it then and others can finish it if they wish. Feel free to create a new PR if you wish :3 |
I have opened a new PR to try to continue the work :) |
This PR closes 11103.
This is my first PR creating a new lint, so I am opening as a draft and thanks for the patience :)
I also have used the simpler
span_lint()
when emitting the lint. If the reviewers think that it is not enough, I can try to evolve the code the use the others span_lint functions.The idea of the lint is to find
insert
in hashmanps inside if staments that are checking if the hashmapcontains
the same value that is being inserted. This is not necessary since you could simply call theinsert
and check for the bool returned if you still need the if statement.changelog: new lint: [
hashset_insert_after_contains
]