Clippy: What and Why

Clippy is a tool known as a linter, which reads through your source code and suggests improvements where your code is suboptimal in various ways. It’s the standard linter for the Rust programming language, and is maintained as a part of the Rust project at https://github.com/rust-lang/rust-clippy. I chose to contribute to Clippy because it’s a tool I’m already familiar with and use very frequently, it’s written in a language (Rust) I’m comfortable working with, and it was suggested as a good starting point for contributing to Rust without having to jump directly into working on the much more complex compiler.

Community Evaluation

Clippy is a sub-project of Rust, and shares much of the same community resources, such as their Code of Conduct and contribution guidelines/procedure. The federation-style community is very structured, with 17 different teams and working groups, a formal RFC process, and heavily automated contribution workflows. As a Rust user, I’ve been tangentially involved in the community for a while, and it’s been a great experience so far. As for contribution resources, there’s not only a lot of documentation on making pull requests and using the various Github bots, but an entire book on the internals of the compiler, and a similar guide for Clippy. The Clippy development guide in particular was extremely helpful, since it covered how to do the changes I ended up working on.

Choosing an issue

I wanted to start with something small that I could quickly fix without having to get too deep into interfacing with the compiler, so I opened up the issues tab on Github and started searching for one that looked good. One of the most recent issues, “assigning_clones should respect MSRV”, seemed good: it was a relatively minor bug that had a simple fix, it didn’t have anyone assigned to it yet, and althouth it didn’t have the good-first-issue tag, I felt confident that I could do it.

the assigning_clones issue on Github

Fixing the bug

The first step was to get set up to do the development: this meant forking the repo, cloning the fork, and making sure building locally worked and all the tests passed. I had a little trouble getting the right packages installed (NixOS can be like that sometimes), but other than that it was as simple as git clone, cargo build, cargo test.

a terminal displaying the passing tests

The next step was to “claim” the issue and mark myself as assigned to work on it. This was done using a command on one of the Github bots:

running @rustbot claim

With the issue claimed and my local development environment set up, I started working on actually fixing the issue. The problem was relatively simple: a particular lint was suggesting to use the method clone_into, which was only stabilized in Rust 1.63, without checking if the code being linted specified a Minimum Supported Rust Version, or MSRV, before 1.63. This lead to it suggesting to use clone_to in situations it shouldn’t be used to maintain compatablity with older versions of Rust. Luckilly, the fix seemed simple: don’t run the lint if the current code specified an MSRV below 1.63. This is a common behaviour to want a lint to have, enough that it has its own section in the Clippy development book.

Clippy MSRV documentation

Adding the MSRV check ended up involving adding a few bits of code scattered across a few different files: declaring the required MSRV, adding an MSRV to the lint’s configuration, the actual check code, and directing the lint to properly handle situations where a section of code has an explicitly-set MSRV. Once the implementation of the fix was in, the last step was to write new tests to confirm it all worked.

screenshot of the test code

The tests are just a pair of functions with specified MSRVs, contaning identical code that should only trigger the lint in the MSRV 1.63 function. The test system runs Clippy over the test code and compares the output to a known-good version, so I had to update that once I confirmed everything worked as expected.

The pull request

Now that the fix was implemented, I pushed it back to my fork on Github and started writing a pull request. The provided template explained how to link the addressed issue and add a changelog, although it didn’t provide much in the way of the overall structure. I ended up looking at a few other pull requests as examples, and then wrote and submitted my own.

assigning_clones pull request

Immidiately, one of the Github bots assigned a reviewer, added a “waiting on review” tag, and sent a message welcoming me to the project.

welcome message from Rustbot

Only a few hours later, the assigned reviewer approved the pull request, and it was merged into the main branch.

the bors Github bot merging the pull request

Bug fixed, code merged, issue closed - we’re done, mission success!

Not so fast…

I returned the next day to a comment on my pull request from the original author of the lint:

comment from the lint author: "Hi, thanks for the PR, but I'm pretty sure that clone_from was not stabilized in 1.63. This should only limit clone_into."

Uh oh. So, it turns out the lint doesn’t just emit suggestions to use clone_to, and will also suggest using clone_from in a different set of cases. In disabling the lint below MSRV 1.63, I disabled not only the improper suggestions, but also correct ones as well. Better fix that.

Fixing the fix

The first thing I did was respond to let them know I was working on a fix:

reply comment saying I'm working on a fix

Now that they knew I wasn’t ghosting them after submitting a faulty bug fix, I got to work making the MSRV check apply correctly. The change ended up being a lot simpler than I expected - there was already a function is_ok_to_suggest that checks if a given pice of code should be linted. Since it aleady had access to whether the suggested function would be clone_from or clone_to, all I had to do was pass the MSRV to it and put the check there. I also updated the tests I had written to confirm that clone_from suggestions were no longer affected by the MSRV. Just like last time, submtting the PR went smoothly, and it was merged a few hours later.

comment from the lint author saying thanks

Conclusion

This was my first time contributing to a major open-source project, and overall I’d say it went quite well. The onboarding, contribution, and development documentation was incredibly helpful, and the community was very welcoming and forgiving even when I made a (in hindsight) quite obvious mistake. The process of making this contribution got me lot more familiar with how Clippy works internally, and I’m definitely going to try and contribute more in the future.