rust-lang / rust-lang/rust-clippy
new lint to remove redundant method calls that have no effect
Open
@S1gn3rs is already working on this.
Since May 7, 2026.
A-lint
- Dominant language
- Rust
- Stars
- 13.5k
- Forks
- 2.2k
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 32
Description
What it does
Detect useless method calls like the second .trim() in string.trim().trim()
Advantage
- Improve readability
- (Possibly) improve performance
Drawbacks
No response
Example
I think covering all the examples below would be excessive, but I’ll list as many as I can think of anyway.
use std::cmp::Ordering;
use std::future::IntoFuture;
use std::net::{IpAddr, Ipv6Addr, TcpStream};
use std::process::Termination;
use std::thread::Builder;
use proc_macro::Span;
let mut vec = vec!['a', 'b', 'c'];
let _ = 1_i32.abs().abs();
let _ = 3.14_f32.floor().floor();
let _ = "Hello".trim().trim();
let _ = "Hello".to_lowercase().to_lowercase();
let _ = b"Hello".to_vec().to_vec();
let _ = (&0 as *const i32).cast::<u32>().cast::<u32>();
let _ = IpAddr::V6(Ipv6Addr::LOCALHOST).to_canonical().to_canonical();
// with arguments (be cautious of side effects)
let _ = 1_i32.max(0).max(0);
let _ = 1_i32.clamp(-1, 1).clamp(-1, 1);
let _ = vec.split_off(1).split_off(1);
let _ = Some(1).and(Some(1)).and(Some(1));
let _ = Ordering::Equal.then(Ordering::Less).then(Ordering::Less);
// rewriting might cause compilation errors (Wrap<Wrap<T>> -> Wrap<T>)
let _ = std::iter::once(1).cycle().cycle();
let _ = std::iter::once(Some(1)).fuse().fuse();
let _ = (0..).take(3).take(3);
let _ = (0..).peekable().peekable();
// some more weird examples for what it’s worth
let _ = Builder::new().stack_size(4096).stack_size(4096);
let _ = Err::<(), _>("oops").report().report();
let _ = Span::call_site().start().start();
let _ = TcpStream::connect("127.0.0.1:8080").as_socket().as_socket(); // Windows only
let _ = async {}.into_future().into_future();
Could be written as:
use std::cmp::Ordering;
use std::future::IntoFuture;
use std::net::{IpAddr, Ipv6Addr, TcpStream};
use std::process::Termination;
use std::thread::Builder;
use proc_macro::Span;
let mut vec = vec!['a', 'b', 'c'];
let _ = 1_i32.abs();
let _ = 3.14_f32.floor();
let _ = "Hello".trim();
let _ = "Hello".to_lowercase();
let _ = b"Hello".to_vec();
let _ = (&0 as *const i32).cast::<u32>();
let _ = IpAddr::V6(Ipv6Addr::LOCALHOST).to_canonical();
// with arguments (be cautious of side effects)
let _ = 1_i32.max(0);
let _ = 1_i32.clamp(-1, 1);
let _ = vec.split_off(1);
let _ = Some(1).and(Some(1));
let _ = Ordering::Equal.then(Ordering::Less);
// rewriting might cause compilation errors (Wrap<Wrap<T>> -> Wrap<T>)
let _ = std::iter::once(1).cycle();
let _ = std::iter::once(Some(1)).fuse();
let _ = (0..).take(3);
let _ = (0..).peekable();
// some more weird examples for what it’s worth
let _ = Builder::new().stack_size(4096);
let _ = Err::<(), _>("oops").report();
let _ = Span::call_site().start();
let _ = TcpStream::connect("127.0.0.1:8080").as_socket(); // Windows only
let _ = async {}.into_future();
Comparison with existing lints
redundant_clone catches useless .to_owned(), .to_string(), and .to_os_string()
#![warn(clippy::nursery)]
use std::ffi::OsStr;
fn main() {
let _ = "Hello".to_owned().to_owned();
let _ = 0.to_string().to_string();
let _ = OsStr::new("foo").to_os_string().to_os_string();
}
warning: redundant clone
--> src/main.rs:6:31
|
6 | let _ = "Hello".to_owned().to_owned();
| ^^^^^^^^^^^ help: remove this
|
note: this value is dropped without further use
--> src/main.rs:6:13
|
6 | let _ = "Hello".to_owned().to_owned();
| ^^^^^^^^^^^^^^^^^^
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone
note: the lint level is defined here
--> src/main.rs:1:9
|
1 | #![warn(clippy::nursery)]
| ^^^^^^^^^^^^^^^
= note: `#[warn(clippy::redundant_clone)]` implied by `#[warn(clippy::nursery)]`
warning: redundant clone
--> src/main.rs:7:26
|
7 | let _ = 0.to_string().to_string();
| ^^^^^^^^^^^^ help: remove this
|
note: this value is dropped without further use
--> src/main.rs:7:13
|
7 | let _ = 0.to_string().to_string();
| ^^^^^^^^^^^^^
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone
warning: redundant clone
--> src/main.rs:8:45
|
8 | let _ = OsStr::new("foo").to_os_string().to_os_string();
| ^^^^^^^^^^^^^^^ help: remove this
|
note: this value is dropped without further use
--> src/main.rs:8:13
|
8 | let _ = OsStr::new("foo").to_os_string().to_os_string();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone
useless_conversion catches useless .into_iter() and From::from()
fn main() {
let _ = Vec::<()>::new().into_iter().into_iter();
let _ = String::from(String::from("Hello"));
}
warning: useless conversion to the same type: `std::vec::IntoIter<()>`
--> src/main.rs:2:13
|
2 | let _ = Vec::<()>::new().into_iter().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `Vec::<()>::new().into_iter()`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion
= note: `#[warn(clippy::useless_conversion)]` on by default
warning: useless conversion to the same type: `std::string::String`
--> src/main.rs:3:13
|
3 | let _ = String::from(String::from("Hello"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `String::from("Hello")`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion
Additional Context
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.