Implement default_mismatches_new lint#16531
Conversation
|
r? @Jarcho rustbot has assigned @Jarcho. Use Why was this reviewer chosen?The reviewer was selected based on:
|
|
Lintcheck changes for cd78473
This comment will be updated if you push new changes |
Some of the examples from Lintcheck seem to match this pattern where |
Yes, I think we should not lint in this case. There will be a time where it will be possible to have |
There was a problem hiding this comment.
First pass at the review.
The part about default_constructed_unit_structs seems independent. If this is the case, can you isolate it and make a new PR explaining what it fixes? (you can assign it to me)
Also, it would be beneficial to cleanup the content of new_without_default.rs in a first commit. It has been written a long time ago, and, for example, we now import struct names from rustc_hir directly instead of using hir::StructName (for example for hir::ExprKind::Ret, we now use ExprKind::Ret).
Keep in mind that those lints, including the new proposed one, are warned by default, so we have to be extra careful in what we put in there.
|
Reminder, once the PR becomes ready for a review, use |
f656707 to
c0e168f
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
c0e168f to
2979df4
Compare
This comment has been minimized.
This comment has been minimized.
bf52143 to
98635f0
Compare
98635f0 to
c705c93
Compare
This comment has been minimized.
This comment has been minimized.
Move is_unit_struct into clippy_utils to use it in the new lint default_mismatches_new
If a type has an auto-derived `Default` trait and a `fn new() -> Self`,
this lint checks if the `new()` method performs custom logic rather
than simply calling the `default()` method.
Users expect the `new()` method to be equivalent to `default()`,
so if the `Default` trait is auto-derived, the `new()` method should
not perform custom logic. Otherwise, there is a risk of different
behavior between the two instantiation methods.
```rust
struct MyStruct(i32);
impl MyStruct {
fn new() -> Self {
Self(42)
}
}
```
Users are unlikely to notice that `MyStruct::new()` and `MyStruct::default()` would produce
different results. The `new()` method should use auto-derived `default()` instead to be consistent:
```rust
struct MyStruct(i32);
impl MyStruct {
fn new() -> Self {
Self::default()
}
}
```
Alternatively, if the `new()` method requires a non-default initialization, implement a custom `Default`.
This also allows you to mark the `new()` implementation as `const`:
```rust
struct MyStruct(i32);
impl MyStruct {
const fn new() -> Self {
Self(42)
}
}
impl Default for MyStruct {
fn default() -> Self {
Self::new()
}
}
```
c705c93 to
cd78473
Compare
|
This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
Re-opening #14234 Implement #14075. Prevents rust-lang/rust#135977.
What it does
If a type has an auto-derived
Defaulttrait and afn new() -> Self, this lint checks if thenew()method performs custom logic rather than callingSelf::default()Why is this bad?
Users expect the
new()method to be equivalent todefault(), so if theDefaulttrait is auto-derived, thenew()method should not perform custom logic. Otherwise, there is a risk of different behavior between the two instantiation methods.Example
Users are unlikely to notice that
MyStruct::new()andMyStruct::default()would produce different results. Thenew()method should use auto-deriveddefault()instead to be consistent:Alternatively, if the
new()method requires non-default initialization, implement a customDefault. This also allows you to mark thenew()implementation asconst:.stderrfile)cargo testpasses locallycargo dev update_lintscargo dev fmtchangelog: [
default_mismatches_new]: new lint to catchfn new() -> Selfmethod not matching theDefaultimplementationNotable cases in the wild
default()andnew()are actually different - likely was a bug that glob team wants to fix (per comments)new()creates cache withVec::with_capacity(), whereasdefault()usesVec::default(). Possibly a bug.Self(())-- should this be ignored?Self { _p: () }forstruct Identity { _p: () }-- probably better to use::default()TODO/TBD
fn new() -> Selfimplementations are OK? (rather than delegating toSelf::default())Selfis a unit typerustc_hir::hir::ImplItemof afn new() -> Self, get the body of that functionreturn Self::default();and no other logic (in all variants likeDefault::default(), etc.clippy_lints/src/default_constructed_unit_structs.rswhile trying to understand its logic - I think we may want to have ais_unit_type(ty)utility function?r? @samueltardieu
See also: non_canonical_partial_ord_impl lint