about summary refs log tree commit diff
path: root/tests
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-12-30 16:37:36 +0000
committerbors <bors@rust-lang.org>2023-12-30 16:37:36 +0000
commitc6aeb28a7b42e1c19e4ecbe60422c3fac0ee2895 (patch)
treee0a64d1bd88d279f29b7c20bb39829368b7a113e /tests
parentb19b5f293edfeca3d03707c39e8289348ce1ba24 (diff)
parentc4a80f2e3e8375ff54826840e2e2a5c53a20e2ce (diff)
downloadrust-c6aeb28a7b42e1c19e4ecbe60422c3fac0ee2895.tar.gz
rust-c6aeb28a7b42e1c19e4ecbe60422c3fac0ee2895.zip
Auto merge of #11865 - yuxqiu:map_unwrap_or_default, r=Jarcho
feat: add `manual_is_variant_and` lint

changelog: add a new lint [`manual_is_variant_and`].
- Replace `option.map(f).unwrap_or_default()` and `result.map(f).unwrap_or_default()` with `option.is_some_and(f)` and `result.is_ok_and(f)` where `f` is a function or closure that returns `bool`.
- MSRV is set to 1.70.0 for this lint; when `is_some_and` and `is_ok_and` was stabilised

---

For example, for the following code:

```rust
let opt = Some(0);
opt.map(|x| x > 1).unwrap_or_default();
```

It suggests to instead write:

```rust
let opt = Some(0);
opt.is_some_and(|x| x > 1)
```
Diffstat (limited to 'tests')
-rw-r--r--tests/ui/manual_is_variant_and.fixed51
-rw-r--r--tests/ui/manual_is_variant_and.rs57
-rw-r--r--tests/ui/manual_is_variant_and.stderr82
3 files changed, 190 insertions, 0 deletions
diff --git a/tests/ui/manual_is_variant_and.fixed b/tests/ui/manual_is_variant_and.fixed
new file mode 100644
index 00000000000..8c34b51103c
--- /dev/null
+++ b/tests/ui/manual_is_variant_and.fixed
@@ -0,0 +1,51 @@
+//@aux-build:option_helpers.rs
+#![warn(clippy::manual_is_variant_and)]
+
+#[macro_use]
+extern crate option_helpers;
+
+#[rustfmt::skip]
+fn option_methods() {
+    let opt = Some(1);
+
+    // Check for `option.map(_).unwrap_or_default()` use.
+    // Single line case.
+    let _ = opt.is_some_and(|x| x > 1);
+    // Multi-line cases.
+    let _ = opt.is_some_and(|x| {
+        x > 1
+    });
+    let _ = opt.is_some_and(|x| x > 1);
+    let _ = opt
+        .is_some_and(|x| x > 1);
+
+    // won't fix because the return type of the closure is not `bool`
+    let _ = opt.map(|x| x + 1).unwrap_or_default();
+
+    let opt2 = Some('a');
+    let _ = opt2.is_some_and(char::is_alphanumeric); // should lint
+    let _ = opt_map!(opt2, |x| x == 'a').unwrap_or_default(); // should not lint
+}
+
+#[rustfmt::skip]
+fn result_methods() {
+    let res: Result<i32, ()> = Ok(1);
+
+    // multi line cases
+    let _ = res.is_ok_and(|x| {
+        x > 1
+    });
+    let _ = res.is_ok_and(|x| x > 1);
+
+    // won't fix because the return type of the closure is not `bool`
+    let _ = res.map(|x| x + 1).unwrap_or_default();
+
+    let res2: Result<char, ()> = Ok('a');
+    let _ = res2.is_ok_and(char::is_alphanumeric); // should lint
+    let _ = opt_map!(res2, |x| x == 'a').unwrap_or_default(); // should not lint
+}
+
+fn main() {
+    option_methods();
+    result_methods();
+}
diff --git a/tests/ui/manual_is_variant_and.rs b/tests/ui/manual_is_variant_and.rs
new file mode 100644
index 00000000000..25b2489d942
--- /dev/null
+++ b/tests/ui/manual_is_variant_and.rs
@@ -0,0 +1,57 @@
+//@aux-build:option_helpers.rs
+#![warn(clippy::manual_is_variant_and)]
+
+#[macro_use]
+extern crate option_helpers;
+
+#[rustfmt::skip]
+fn option_methods() {
+    let opt = Some(1);
+
+    // Check for `option.map(_).unwrap_or_default()` use.
+    // Single line case.
+    let _ = opt.map(|x| x > 1)
+        // Should lint even though this call is on a separate line.
+        .unwrap_or_default();
+    // Multi-line cases.
+    let _ = opt.map(|x| {
+        x > 1
+    }
+    ).unwrap_or_default();
+    let _ = opt.map(|x| x > 1).unwrap_or_default();
+    let _ = opt
+        .map(|x| x > 1)
+        .unwrap_or_default();
+
+    // won't fix because the return type of the closure is not `bool`
+    let _ = opt.map(|x| x + 1).unwrap_or_default();
+
+    let opt2 = Some('a');
+    let _ = opt2.map(char::is_alphanumeric).unwrap_or_default(); // should lint
+    let _ = opt_map!(opt2, |x| x == 'a').unwrap_or_default(); // should not lint
+}
+
+#[rustfmt::skip]
+fn result_methods() {
+    let res: Result<i32, ()> = Ok(1);
+
+    // multi line cases
+    let _ = res.map(|x| {
+        x > 1
+    }
+    ).unwrap_or_default();
+    let _ = res.map(|x| x > 1)
+        .unwrap_or_default();
+
+    // won't fix because the return type of the closure is not `bool`
+    let _ = res.map(|x| x + 1).unwrap_or_default();
+
+    let res2: Result<char, ()> = Ok('a');
+    let _ = res2.map(char::is_alphanumeric).unwrap_or_default(); // should lint
+    let _ = opt_map!(res2, |x| x == 'a').unwrap_or_default(); // should not lint
+}
+
+fn main() {
+    option_methods();
+    result_methods();
+}
diff --git a/tests/ui/manual_is_variant_and.stderr b/tests/ui/manual_is_variant_and.stderr
new file mode 100644
index 00000000000..c243de098dc
--- /dev/null
+++ b/tests/ui/manual_is_variant_and.stderr
@@ -0,0 +1,82 @@
+error: called `map(<f>).unwrap_or_default()` on an `Option` value
+  --> $DIR/manual_is_variant_and.rs:13:17
+   |
+LL |       let _ = opt.map(|x| x > 1)
+   |  _________________^
+LL | |         // Should lint even though this call is on a separate line.
+LL | |         .unwrap_or_default();
+   | |____________________________^ help: use: `is_some_and(|x| x > 1)`
+   |
+   = note: `-D clippy::manual-is-variant-and` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::manual_is_variant_and)]`
+
+error: called `map(<f>).unwrap_or_default()` on an `Option` value
+  --> $DIR/manual_is_variant_and.rs:17:17
+   |
+LL |       let _ = opt.map(|x| {
+   |  _________________^
+LL | |         x > 1
+LL | |     }
+LL | |     ).unwrap_or_default();
+   | |_________________________^
+   |
+help: use
+   |
+LL ~     let _ = opt.is_some_and(|x| {
+LL +         x > 1
+LL ~     });
+   |
+
+error: called `map(<f>).unwrap_or_default()` on an `Option` value
+  --> $DIR/manual_is_variant_and.rs:21:17
+   |
+LL |     let _ = opt.map(|x| x > 1).unwrap_or_default();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_some_and(|x| x > 1)`
+
+error: called `map(<f>).unwrap_or_default()` on an `Option` value
+  --> $DIR/manual_is_variant_and.rs:23:10
+   |
+LL |           .map(|x| x > 1)
+   |  __________^
+LL | |         .unwrap_or_default();
+   | |____________________________^ help: use: `is_some_and(|x| x > 1)`
+
+error: called `map(<f>).unwrap_or_default()` on an `Option` value
+  --> $DIR/manual_is_variant_and.rs:30:18
+   |
+LL |     let _ = opt2.map(char::is_alphanumeric).unwrap_or_default(); // should lint
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_some_and(char::is_alphanumeric)`
+
+error: called `map(<f>).unwrap_or_default()` on a `Result` value
+  --> $DIR/manual_is_variant_and.rs:39:17
+   |
+LL |       let _ = res.map(|x| {
+   |  _________________^
+LL | |         x > 1
+LL | |     }
+LL | |     ).unwrap_or_default();
+   | |_________________________^
+   |
+help: use
+   |
+LL ~     let _ = res.is_ok_and(|x| {
+LL +         x > 1
+LL ~     });
+   |
+
+error: called `map(<f>).unwrap_or_default()` on a `Result` value
+  --> $DIR/manual_is_variant_and.rs:43:17
+   |
+LL |       let _ = res.map(|x| x > 1)
+   |  _________________^
+LL | |         .unwrap_or_default();
+   | |____________________________^ help: use: `is_ok_and(|x| x > 1)`
+
+error: called `map(<f>).unwrap_or_default()` on a `Result` value
+  --> $DIR/manual_is_variant_and.rs:50:18
+   |
+LL |     let _ = res2.map(char::is_alphanumeric).unwrap_or_default(); // should lint
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_ok_and(char::is_alphanumeric)`
+
+error: aborting due to 8 previous errors
+