Auto merge of #10534 - samueltardieu:lines-filter-map-ok, r=llogiq

Flag `bufreader.lines().filter_map(Result::ok)` as suspicious

This lint detects a problem that happened recently in https://github.com/uutils/coreutils and is described in https://github.com/rust-lang/rust/issues/64144.

changelog: [`lines_filter_map_ok`]: new lint
This commit is contained in:
bors 2023-04-01 12:41:08 +00:00
commit ac4838c554
8 changed files with 215 additions and 0 deletions

View file

@ -0,0 +1,29 @@
// run-rustfix
#![allow(unused, clippy::map_identity)]
#![warn(clippy::lines_filter_map_ok)]
use std::io::{self, BufRead, BufReader};
fn main() -> io::Result<()> {
let f = std::fs::File::open("/")?;
// Lint
BufReader::new(f).lines().map_while(Result::ok).for_each(|_| ());
// Lint
let f = std::fs::File::open("/")?;
BufReader::new(f).lines().map_while(Result::ok).for_each(|_| ());
let s = "foo\nbar\nbaz\n";
// Lint
io::stdin().lines().map_while(Result::ok).for_each(|_| ());
// Lint
io::stdin().lines().map_while(Result::ok).for_each(|_| ());
// Do not lint (not a `Lines` iterator)
io::stdin()
.lines()
.map(std::convert::identity)
.filter_map(|x| x.ok())
.for_each(|_| ());
// Do not lint (not a `Result::ok()` extractor)
io::stdin().lines().filter_map(|x| x.err()).for_each(|_| ());
Ok(())
}

View file

@ -0,0 +1,29 @@
// run-rustfix
#![allow(unused, clippy::map_identity)]
#![warn(clippy::lines_filter_map_ok)]
use std::io::{self, BufRead, BufReader};
fn main() -> io::Result<()> {
let f = std::fs::File::open("/")?;
// Lint
BufReader::new(f).lines().filter_map(Result::ok).for_each(|_| ());
// Lint
let f = std::fs::File::open("/")?;
BufReader::new(f).lines().flat_map(Result::ok).for_each(|_| ());
let s = "foo\nbar\nbaz\n";
// Lint
io::stdin().lines().filter_map(Result::ok).for_each(|_| ());
// Lint
io::stdin().lines().filter_map(|x| x.ok()).for_each(|_| ());
// Do not lint (not a `Lines` iterator)
io::stdin()
.lines()
.map(std::convert::identity)
.filter_map(|x| x.ok())
.for_each(|_| ());
// Do not lint (not a `Result::ok()` extractor)
io::stdin().lines().filter_map(|x| x.err()).for_each(|_| ());
Ok(())
}

View file

@ -0,0 +1,51 @@
error: `filter_map()` will run forever if the iterator repeatedly produces an `Err`
--> $DIR/lines_filter_map_ok.rs:11:31
|
LL | BufReader::new(f).lines().filter_map(Result::ok).for_each(|_| ());
| ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)`
|
note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error
--> $DIR/lines_filter_map_ok.rs:11:5
|
LL | BufReader::new(f).lines().filter_map(Result::ok).for_each(|_| ());
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: `-D clippy::lines-filter-map-ok` implied by `-D warnings`
error: `flat_map()` will run forever if the iterator repeatedly produces an `Err`
--> $DIR/lines_filter_map_ok.rs:14:31
|
LL | BufReader::new(f).lines().flat_map(Result::ok).for_each(|_| ());
| ^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)`
|
note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error
--> $DIR/lines_filter_map_ok.rs:14:5
|
LL | BufReader::new(f).lines().flat_map(Result::ok).for_each(|_| ());
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: `filter_map()` will run forever if the iterator repeatedly produces an `Err`
--> $DIR/lines_filter_map_ok.rs:17:25
|
LL | io::stdin().lines().filter_map(Result::ok).for_each(|_| ());
| ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)`
|
note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error
--> $DIR/lines_filter_map_ok.rs:17:5
|
LL | io::stdin().lines().filter_map(Result::ok).for_each(|_| ());
| ^^^^^^^^^^^^^^^^^^^
error: `filter_map()` will run forever if the iterator repeatedly produces an `Err`
--> $DIR/lines_filter_map_ok.rs:19:25
|
LL | io::stdin().lines().filter_map(|x| x.ok()).for_each(|_| ());
| ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)`
|
note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error
--> $DIR/lines_filter_map_ok.rs:19:5
|
LL | io::stdin().lines().filter_map(|x| x.ok()).for_each(|_| ());
| ^^^^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors