rust-lang / rust-lang/rust-clippy

clippy::new_without_default_derive triggers and shouldn't

Open
#3,697 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

C-bug E-medium I-false-positive L-suggestion
Dominant language
Rust
Stars
13.5k
Forks
2.2k
Avg merge
2d 10h
Merged PRs (30d)
32

Description

$ cargo -V
cargo 1.33.0-nightly (907c0febe 2019-01-20)
$ rustc -V
rustc 1.33.0-nightly (01f8e25b1 2019-01-24)
$ cargo clippy -V
clippy 0.0.212 (c5325063 2019-01-25)

Hi. After going through most of chapter 17.3, we end up with something like this:

fn main() {
    let mut post = Post::new();

    post.add_text("Hello");
    assert_eq!("", post.content());

    post.request_review();
    assert_eq!("", post.content());

    post.approve();
    assert_eq!("Hello", post.content());
}

pub struct Post {
    state: Option<Box<dyn State>>,
    content: String,
}

impl Post {
    pub fn new() -> Self {
        Post {
            state: Some(Box::new(Draft {})),
            content: String::new(),
        }
    }

    fn content(&self) -> &str {
        self.state.as_ref().unwrap().content(&self)
    }

    fn add_text(&mut self, text: &str) {
        self.content.push_str(text)
    }

    fn request_review(&mut self) {
        if let Some(s) = self.state.take() {
            self.state = Some(s.request_review())
        }
    }

    fn approve(&mut self) {
        if let Some(s) = self.state.take() {
            self.state = Some(s.approve())
        }
    }
}

trait State {
    fn request_review(self: Box<Self>) -> Box<dyn State>;

    fn approve(self: Box<Self>) -> Box<dyn State>;

    fn content<'a>(&self, _post: &'a Post) -> &'a str {
        ""
    }
}

struct Draft {}

impl State for Draft {
    fn request_review(self: Box<Self>) -> Box<dyn State> {
        Box::new(PendingReview {})
    }
    
    fn approve(self: Box<Self>) -> Box<dyn State> {
        self
    }
}

struct PendingReview {}

impl State for PendingReview {
    fn request_review(self: Box<Self>) -> Box<dyn State> {
        self
    }

    fn approve(self: Box<Self>) -> Box<dyn State> {
        Box::new(Published {})
    }
}

struct Published {}

impl State for Published {
    fn request_review(self: Box<Self>) -> Box<dyn State> {
        self
    }

    fn approve(self: Box<Self>) -> Box<dyn State> {
        self
    }

    fn content<'a>(&self, post: &'a Post) -> &'a str {
        &post.content
    }
}

and if we run cargo clippy, we get a warning that I believe we shouldn't get:

warning: you should consider deriving a `Default` implementation for `Post`
  --> src/main.rs:20:5
   |
20 | /     pub fn new() -> Self {
21 | |         Post {
22 | |             state: Some(Box::new(Draft {})),
23 | |             content: String::new(),
24 | |         }
25 | |     }
   | |_____^
   |
   = note: #[warn(clippy::new_without_default)] on by default
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default
help: try this
   |
14 | #[derive(Default)]
   |

Adding #[derive(Default)] to struct Pub without further changes is enough for the warning to disappear (which looks like a bug by itself); and if we replace the body of fn new with Default::default(), as suggested here, we get a different behavior.

(BTW, this warning only triggers if the declarations of both struct Pub and fn new are prefixed with pub, as in the example above).

This might be related with #1579.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the report with the Rust example in src/main.rs by running cargo clippy with the listed toolchain. Then trace the new_without_default lint and its derive suggestion, and verify that the public Post::new case no longer produces an incorrect warning or recommendation.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.