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 option_as_ref_deref lint #4945

Merged
merged 1 commit into from
Jan 23, 2020
Merged

add option_as_ref_deref lint #4945

merged 1 commit into from
Jan 23, 2020

Conversation

basil-cow
Copy link
Contributor

changelog: add a new lint that lints option.as_ref().map(Deref::deref) (and similar calls), which could be expressed more succinctly as option.as_deref[_mut](). Closes #4918.

@ghost
Copy link

ghost commented Dec 23, 2019

I found a case where the lint gives a bad suggestion.

fn main() {
    let s: String = String::from("STRING");

    let _: Option<&str> = Some(&s).as_ref().map(|x| x.as_str());
    let _: Option<&String> = Some(&s).as_deref();
}
warning: called `.as_ref().map(Deref::deref)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `Some(&s).as_deref()` instead
 --> src/main.rs:6:27
  |
6 |     let _: Option<&str> = Some(&s).as_ref().map(|x| x.as_str());
  |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(&s).as_deref()`

This suggestion won't work because the type of Some(&s).as_ref().map(|x| x.as_str()) isn't the same type as Some(&s).as_deref().

@basil-cow
Copy link
Contributor Author

I knew deref coercion would screw me over somewhere, should've created a test for that myself, thanks for noticing. I thought coercion is already explicit in hir but I guess it is not?

@flip1995
Copy link
Member

Maybe we can check the type of x.as_ref().map(..) calls and check if expr_ty(x) has Deref::Target of the type of the map(..) call and only lint in this case.

@flip1995 flip1995 added the S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) label Dec 23, 2019
@basil-cow
Copy link
Contributor Author

@flip1995 I am a little puzzled with getting <T as Deref>::Target type, maybe you can point me in the right direction?

@ghost
Copy link

ghost commented Dec 24, 2019

I think you can just check if x (i.e. the as_str() receiver) has any adjustments applied to it.

Here is my reasoning...

o.as_def() is o.as_ref().map(|x| x.deref()). So replacing o.as_ref().map(|x| x.as_str()); with o.as_deref() boils downs to whether you can replace x.as_str() with x.deref(). IMO, this should be the safe as long as there are no adjustments (autorefs, autoderefs) applied to x in x.as_str().

@basil-cow
Copy link
Contributor Author

basil-cow commented Dec 24, 2019

@mikerite That was my reasoning as well when I was implementing it. Currently I am checking whether the first argument to as_str is a QPath that resolves to the input parameter of the closure. I thought that would be enough, bur apparently autoderef information is stored somewhere else (and not in the coercion table, because that one is empty in tests) and is not explicitly converted to hir (x.as_str() is still x.as_str() in hir and not (*x).as_str()). I think I'll just check that x's type is the same as as_str's input parameter type (but I would welcome a more straightforward solution)

@bors
Copy link
Contributor

bors commented Dec 24, 2019

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

@ghost
Copy link

ghost commented Dec 24, 2019

Try the is_adjusted method in utils.

@flip1995
Copy link
Member

I am a little puzzled with getting <T as Deref>::Target type, maybe you can point me in the right direction?

I'm not sure myself. Somehow get the Item of the Deref impl of the type of x and the check the associated item Target. For types not implementing Deref explicitly is as easy as calling builtin_deref. But maybe this is too hard, idk.

@basil-cow basil-cow force-pushed the as_deref branch 2 times, most recently from d9720d5 to db0a3a6 Compare December 24, 2019 16:17
@basil-cow
Copy link
Contributor Author

I presumably fixed it, can anybody think of any more tests to add?

@flip1995
Copy link
Member

A macro test would be good

@bors
Copy link
Contributor

bors commented Dec 31, 2019

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

@pickfire
Copy link
Contributor

pickfire commented Jan 5, 2020

Maybe as_ref().map(|c| &**c) to as_deref() too? Got it from @lzutao

@bors
Copy link
Contributor

bors commented Jan 13, 2020

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

Copy link
Member

@flip1995 flip1995 left a comment

Choose a reason for hiding this comment

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

I just realized, that I reviewed this PR weeks ago, but never pressed "Submit review". Sorry for the long wait time...

Comment on lines 2984 to 3073
span_lint_and_then(cx, OPTION_AS_REF_DEREF, expr.span, &msg, |db| {
db.span_suggestion(expr.span, &suggestion, hint, Applicability::MachineApplicable);
});
Copy link
Member

Choose a reason for hiding this comment

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

Why not just span_lint_and_sugg? Everything else LGTM.

@basil-cow
Copy link
Contributor Author

Lets merge this for now, I'll probably add |x| &**x later

@flip1995
Copy link
Member

@bors r+

@bors
Copy link
Contributor

bors commented Jan 23, 2020

📌 Commit 796958c has been approved by flip1995

@bors
Copy link
Contributor

bors commented Jan 23, 2020

⌛ Testing commit 796958c with merge 6763447...

bors added a commit that referenced this pull request Jan 23, 2020
add `option_as_ref_deref` lint

changelog: add a new lint that lints `option.as_ref().map(Deref::deref)` (and similar calls), which could be expressed more succinctly as `option.as_deref[_mut]()`. Closes #4918.
@bors
Copy link
Contributor

bors commented Jan 23, 2020

☀️ Test successful - checks-travis, status-appveyor
Approved by: flip1995
Pushing 6763447 to master...

@bors bors merged commit 796958c into rust-lang:master Jan 23, 2020
@shepmaster
Copy link
Member

Lets merge this for now, I'll probably add |x| &**x later

Is this being tracked anywhere? That's how I tend to write this case.

@flip1995
Copy link
Member

Good catch! It is now: #5367

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.

Lint for using Option::as_deref
5 participants