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

Improve redundant_slicing lint #8218

Merged
merged 4 commits into from
Feb 17, 2022
Merged

Conversation

Jarcho
Copy link
Contributor

@Jarcho Jarcho commented Jan 3, 2022

fixes #7972
fixes #7257

This can supersede #7976

changelog: Fix suggestion for redundant_slicing when re-borrowing for a method call
changelog: New lint deref_as_slicing

@rust-highfive
Copy link

r? @camsteffen

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Jan 3, 2022
@Jarcho Jarcho force-pushed the redundant_slicing_deref branch 2 times, most recently from c242ef2 to 2c1f2ff Compare January 3, 2022 21:11
@camsteffen
Copy link
Contributor

Linting "slice instead of deref" is more picky than linting "slice has no effect", so I think this should be a new lint. Named deref_by_slicing perhaps?

And then I'm not sure if it should be pedantic or restriction. I think some people may actually prefer the slicing operator since it makes the type of the expression more apparent. There's also a third option - to use .as_slice() (if available). So people may prefer these three options in any order and it's not clear to me that any is more idiomatic than another.

@Jarcho
Copy link
Contributor Author

Jarcho commented Jan 6, 2022

That is a fair point. I'd say pedantic for it, but restriction would also be reasonable.

I'd say &x[..] changing &&T to &T would still fall under redundant_slicing

@camsteffen
Copy link
Contributor

@rust-lang/clippy thoughts? Should &vec[..] to &*vec or vec.to_slice() be pedantic or restriction?

@camsteffen
Copy link
Contributor

I'd say &x[..] changing &&T to &T would still fall under redundant_slicing

Sounds good. That would be &&[T] to &[T].

@Manishearth
Copy link
Member

Manishearth commented Jan 6, 2022

@rust-lang/clippy thoughts? Should &vec[..] to &*vec or vec.to_slice() be pedantic or restriction?

restriction I think. Pedantic is kinda fine but I think we need to have a reason for it

If it's going to be a restriction lint I suspect we should wait for people to ask us for it

@Jarcho
Copy link
Contributor Author

Jarcho commented Jan 6, 2022

#7257 kind of asked for it. Although I'm sure it was assuming letting auto-deref take care of things rather than explicitly dereferencing.

@camsteffen
Copy link
Contributor

I'm also thinking restriction - feels opinionated/controversial. But I do think having the lint would be good, especially since the implementation easily fits in with redundant_slicing.

@Jarcho Jarcho force-pushed the redundant_slicing_deref branch 4 times, most recently from bd637f2 to ac282d8 Compare January 11, 2022 19:33
@camsteffen
Copy link
Contributor

What do you think about the name full_slicing? This terminology appears in slice docs. IIUC the lint pretty much bans any usage of [..].

Also don't forget to add a test case where the sliced expression is &&Vec<_>. This is an exceptionally picky case, but I think it's consistent to include it.

@flip1995
Copy link
Member

flip1995 commented Jan 12, 2022

Should &vec[..] to &*vec or vec.to_slice() be pedantic or restriction?

I would say restriction. &vec[..] is a too common of a pattern for Clippy to suggest that it is bad (even for a pedantic lint), IMO.

@Jarcho
Copy link
Contributor Author

Jarcho commented Jan 12, 2022

Between the two lints almost all slicing with RangeFull would be banned. There might be the odd type that doesn't implement Deref, or just return itself. There's none in std at least.

The problem with the full_slicing name is it doesn't mention only triggering when it overlaps with a Deref impl. The notable example being the slice type itself.

@camsteffen
Copy link
Contributor

WRT naming, I think it's fine to assume the convention: index operator with a range is called "slicing" and it returns a slice.

I think redundant_slicing represents a subset of full_slicing conceptually, and when that happens it's not necessary to force the lint definitions to be mutually exclusive. Otherwise in this case you end up with "bans full slicing except when its a noop".

@Jarcho
Copy link
Contributor Author

Jarcho commented Jan 12, 2022

There's still the case where the type has full slicing that changes the type, but doesn't impl Deref for whatever reason, or where slicing has a different type than the deref. I don't think either case is particularly common, but those are cases where the name would be incorrect.

@camsteffen
Copy link
Contributor

Fair point. How about deref_by_slicing? slice_as_deref makes me think of as.

@Jarcho
Copy link
Contributor Author

Jarcho commented Jan 13, 2022

That works.

clippy_lints/src/redundant_slicing.rs Outdated Show resolved Hide resolved
@@ -520,7 +520,7 @@ fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item<'_>) -> Opt
if_chain! {
// Identify attribute
if let ast::AttrKind::Normal(ref attr_kind, _) = &attr.kind;
if let [tool_name, attr_name] = &attr_kind.path.segments[..];
if let [tool_name, attr_name] = &*attr_kind.path.segments;
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd prefer not to "fix" all these since it's a restriction lint. Please also revert any such changes in the tests unless you think it is improving the quality of the test.

@camsteffen camsteffen 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 Jan 15, 2022
LL | let _ = &(&v[..])[..]; // Outer borrow is redundant
| ^^^^^^^^^^^^^ help: use the original value instead: `(&v[..])`
LL | let _ = &(&*v)[..]; // Outer borrow is redundant
| ^^^^^^^^^^ help: use the original value instead: `(&*v)`
Copy link
Contributor

Choose a reason for hiding this comment

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

It's been a while since I looked at this PR. I believe if a * is suggested, it should be a deref_by_slicing case?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The suggested change is from &(&*v)[..] -> (&*v) where v is a Vec<_>. The lint isn't suggesting to add a dereference here, it was already there to start with.

Copy link
Contributor

Choose a reason for hiding this comment

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

Apparrently I can't tell the difference between the commit diff and the rust output diff 🤦. But what about the error at the bottom of this file (same question)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll assume you're referring to &slice_ref[..]. slice_ref is a &&[_]. Full slicing is the same as just removing a reference in this case.

Copy link
Contributor

Choose a reason for hiding this comment

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

Below that is

error: redundant slicing of the whole range
  --> $DIR/redundant_slicing.rs:45:13
   |
LL |     let _ = (&bytes[..]).read_to_end(&mut vec![]).unwrap();
   |             ^^^^^^^^^^^^ help: reborrow the original value instead: `(&*bytes)`

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If anything the previous one is much more of a deref-by-slicing. This is very much a slice-to-get-a-new-value-so-we-don't-modify-the-current-one (really flows of the tongue there).

I think leaving redundant_slicing to only handle cases where it's doing nothing and can be fully removed is fine, but deref_by_slicing is not really a good spot to put the remaining cases. That would mean having a name for a new lint (as precise as the name earlier is, I don't want to fight for longest lint name).

Copy link
Contributor

Choose a reason for hiding this comment

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

You could call it slice-to-deref-to-get-a-new-borrow-of... You can put a lot of new names on it but ultimately it just changes &[u8] to [u8] before the borrow operator applies. I don't see how it is not a deref. The suggestion literally replaces the slicing with a deref operator which has the exact same effect. If I enabled deref_by_slicing in my code, I'd consider it a bug if this case were not included.

I think leaving redundant_slicing to only handle cases where it's doing nothing and can be fully removed is fine

That is the most important thing since it is warn-by-default.

Copy link
Contributor Author

@Jarcho Jarcho Feb 9, 2022

Choose a reason for hiding this comment

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

We're talking about two slightly different things here. I'm talking about the entire expression &x[..] not just x[..]. x[..] is just *x.index(..) so it will almost always be a deref. In this case the deref part is the only effect being used, so I guess that fits under deref_by_slicing.

I'm not sure why you don't take issue with the &&T -> &T case being under redundant_slicing.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure why you don't take issue with the &&T -> &T case being under redundant_slicing.

Honestly I was just focusing on the other case. Yeah that one probably should be treated in the same way.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll move that all to deref_as_slice then. I still think the re-borrowing case is different enough to warrant it's own lint, but that can be dealt with at another time.

@bors
Copy link
Collaborator

bors commented Feb 10, 2022

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

@Jarcho Jarcho force-pushed the redundant_slicing_deref branch 2 times, most recently from 2308856 to 46353f8 Compare February 13, 2022 23:58
@camsteffen
Copy link
Contributor

Thanks!

@bors r+

@bors
Copy link
Collaborator

bors commented Feb 16, 2022

📌 Commit 46353f8 has been approved by camsteffen

@camsteffen
Copy link
Contributor

@bors r-

Sorry, probably should squash some?

* Lint when slicing triggers auto-deref
* Lint when slicing returns the same type as dereferencing
@camsteffen
Copy link
Contributor

@bors r+

@bors
Copy link
Collaborator

bors commented Feb 17, 2022

📌 Commit 7724d67 has been approved by camsteffen

@bors
Copy link
Collaborator

bors commented Feb 17, 2022

⌛ Testing commit 7724d67 with merge 668b3e4...

@bors
Copy link
Collaborator

bors commented Feb 17, 2022

☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test
Approved by: camsteffen
Pushing 668b3e4 to master...

@bors bors merged commit 668b3e4 into rust-lang:master Feb 17, 2022
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
6 participants