diff options
| author | Philipp Krones <hello@philkrones.com> | 2025-07-10 20:25:36 +0200 |
|---|---|---|
| committer | Philipp Krones <hello@philkrones.com> | 2025-07-10 20:25:36 +0200 |
| commit | ee400afc5156e175cae4e7a167d36d7fbda46be7 (patch) | |
| tree | 13d949c6bb2a73271a718c9e49cef563d531efcd /src/tools/clippy/tests | |
| parent | 78a6e132984dba0303ebad7dcfd1305c93ad5835 (diff) | |
| parent | cdbbf3afda0b1bf51568b368f629b1d828507f98 (diff) | |
Merge commit 'cdbbf3afda0b1bf51568b368f629b1d828507f98' into clippy-subtree-update
Diffstat (limited to 'src/tools/clippy/tests')
69 files changed, 1810 insertions, 128 deletions
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index cefe654fef6..aa786334711 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -16,8 +16,10 @@ use test_utils::IS_RUSTC_TEST_SUITE; use ui_test::custom_flags::Flag; use ui_test::custom_flags::edition::Edition; use ui_test::custom_flags::rustfix::RustfixMode; +use ui_test::dependencies::DependencyBuilder; use ui_test::spanned::Spanned; -use ui_test::{Args, CommandBuilder, Config, Match, error_on_output_conflict, status_emitter}; +use ui_test::status_emitter::StatusEmitter; +use ui_test::{Args, CommandBuilder, Config, Match, error_on_output_conflict}; use std::collections::{BTreeMap, HashMap}; use std::env::{self, set_var, var_os}; @@ -27,46 +29,26 @@ use std::path::{Path, PathBuf}; use std::sync::mpsc::{Sender, channel}; use std::{fs, iter, thread}; -// Test dependencies may need an `extern crate` here to ensure that they show up -// in the depinfo file (otherwise cargo thinks they are unused) -extern crate futures; -extern crate if_chain; -extern crate itertools; -extern crate parking_lot; -extern crate quote; -extern crate syn; -extern crate tokio; - mod test_utils; -/// All crates used in UI tests are listed here -static TEST_DEPENDENCIES: &[&str] = &[ - "clippy_config", - "clippy_lints", - "clippy_utils", - "futures", - "if_chain", - "itertools", - "parking_lot", - "quote", - "regex", - "serde_derive", - "serde", - "syn", - "tokio", -]; - -/// Produces a string with an `--extern` flag for all UI test crate -/// dependencies. +/// All crates used in internal UI tests are listed here. +/// We directly re-use these crates from their normal clippy builds, so we don't have them +/// in `clippy_test_devs`. That saves a lot of time but also means they don't work in a stage 1 +/// test in rustc bootstrap. +static INTERNAL_TEST_DEPENDENCIES: &[&str] = &["clippy_config", "clippy_lints", "clippy_utils"]; + +/// Produces a string with an `--extern` flag for all `INTERNAL_TEST_DEPENDENCIES`. /// /// The dependency files are located by parsing the depinfo file for this test /// module. This assumes the `-Z binary-dep-depinfo` flag is enabled. All test /// dependencies must be added to Cargo.toml at the project root. Test /// dependencies that are not *directly* used by this test module require an /// `extern crate` declaration. -fn extern_flags() -> Vec<String> { +fn internal_extern_flags() -> Vec<String> { + let current_exe_path = env::current_exe().unwrap(); + let deps_path = current_exe_path.parent().unwrap(); let current_exe_depinfo = { - let mut path = env::current_exe().unwrap(); + let mut path = current_exe_path.clone(); path.set_extension("d"); fs::read_to_string(path).unwrap() }; @@ -88,7 +70,7 @@ fn extern_flags() -> Vec<String> { Some((name, path_str)) }; if let Some((name, path)) = parse_name_path() - && TEST_DEPENDENCIES.contains(&name) + && INTERNAL_TEST_DEPENDENCIES.contains(&name) { // A dependency may be listed twice if it is available in sysroot, // and the sysroot dependencies are listed first. As of the writing, @@ -96,7 +78,7 @@ fn extern_flags() -> Vec<String> { crates.insert(name, path); } } - let not_found: Vec<&str> = TEST_DEPENDENCIES + let not_found: Vec<&str> = INTERNAL_TEST_DEPENDENCIES .iter() .copied() .filter(|n| !crates.contains_key(n)) @@ -111,6 +93,7 @@ fn extern_flags() -> Vec<String> { crates .into_iter() .map(|(name, path)| format!("--extern={name}={path}")) + .chain([format!("-Ldependency={}", deps_path.display())]) .collect() } @@ -119,7 +102,6 @@ const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal"); struct TestContext { args: Args, - extern_flags: Vec<String>, diagnostic_collector: Option<DiagnosticCollector>, collector_thread: Option<thread::JoinHandle<()>>, } @@ -134,7 +116,6 @@ impl TestContext { .unzip(); Self { args, - extern_flags: extern_flags(), diagnostic_collector, collector_thread, } @@ -158,6 +139,15 @@ impl TestContext { }; let defaults = config.comment_defaults.base(); defaults.set_custom("edition", Edition("2024".into())); + defaults.set_custom( + "dependencies", + DependencyBuilder { + program: CommandBuilder::cargo(), + crate_manifest_path: Path::new("clippy_test_deps").join("Cargo.toml"), + build_std: None, + bless_lockfile: self.args.bless, + }, + ); defaults.exit_status = None.into(); if mandatory_annotations { defaults.require_annotations = Some(Spanned::dummy(true)).into(); @@ -182,12 +172,10 @@ impl TestContext { "-Zui-testing", "-Zdeduplicate-diagnostics=no", "-Dwarnings", - &format!("-Ldependency={}", deps_path.display()), ] .map(OsString::from), ); - config.program.args.extend(self.extern_flags.iter().map(OsString::from)); // Prevent rustc from creating `rustc-ice-*` files the console output is enough. config.program.envs.push(("RUSTC_ICE".into(), Some("0".into()))); @@ -217,7 +205,7 @@ fn run_ui(cx: &TestContext) { vec![config], ui_test::default_file_filter, ui_test::default_per_file_config, - status_emitter::Text::from(cx.args.format), + Box::<dyn StatusEmitter>::from(cx.args.format), ) .unwrap(); } @@ -227,13 +215,17 @@ fn run_internal_tests(cx: &TestContext) { return; } let mut config = cx.base_config("ui-internal", true); + config + .program + .args + .extend(internal_extern_flags().iter().map(OsString::from)); config.bless_command = Some("cargo uitest --features internal -- -- --bless".into()); ui_test::run_tests_generic( vec![config], ui_test::default_file_filter, ui_test::default_per_file_config, - status_emitter::Text::from(cx.args.format), + Box::<dyn StatusEmitter>::from(cx.args.format), ) .unwrap(); } @@ -257,7 +249,7 @@ fn run_ui_toml(cx: &TestContext) { .envs .push(("CLIPPY_CONF_DIR".into(), Some(path.parent().unwrap().into()))); }, - status_emitter::Text::from(cx.args.format), + Box::<dyn StatusEmitter>::from(cx.args.format), ) .unwrap(); } @@ -304,7 +296,7 @@ fn run_ui_cargo(cx: &TestContext) { .then(|| ui_test::default_any_file_filter(path, config) && !ignored_32bit(path)) }, |_config, _file_contents| {}, - status_emitter::Text::from(cx.args.format), + Box::<dyn StatusEmitter>::from(cx.args.format), ) .unwrap(); } diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr index 20cdff5fcd1..cebfc48a884 100644 --- a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr +++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr @@ -450,5 +450,13 @@ help: consider removing the safety comment LL | // SAFETY: unnecessary_safety_comment triggers here | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 52 previous errors +error: unsafe block missing a safety comment + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:733:12 + | +LL | return unsafe { h() }; + | ^^^^^^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: aborting due to 53 previous errors diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs index 91a02bc3d7c..a2d7c1b6c79 100644 --- a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs @@ -723,4 +723,15 @@ fn issue_13039() { _ = unsafe { foo() } } +fn rfl_issue15034() -> i32 { + unsafe fn h() -> i32 { + 1i32 + } + // This shouldn't lint with accept-comment-above-attributes! Thus fixing a false positive! + // SAFETY: My safety comment! + #[allow(clippy::unnecessary_cast)] + return unsafe { h() }; + //~[disabled]^ ERROR: unsafe block missing a safety comment +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed index 3ba2eea59f0..3f6e5245b87 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed +++ b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed @@ -47,3 +47,9 @@ fn implicit_cast() { // Do not lint references to temporaries core::ptr::eq(&0i32, &1i32); } + +fn issue_15141() { + let a = String::new(); + // Don't lint cast to dyn trait pointers + let b = &a as *const dyn std::any::Any; +} diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.rs b/src/tools/clippy/tests/ui/borrow_as_ptr.rs index 8cdd0512da5..20f4f40e001 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr.rs +++ b/src/tools/clippy/tests/ui/borrow_as_ptr.rs @@ -47,3 +47,9 @@ fn implicit_cast() { // Do not lint references to temporaries core::ptr::eq(&0i32, &1i32); } + +fn issue_15141() { + let a = String::new(); + // Don't lint cast to dyn trait pointers + let b = &a as *const dyn std::any::Any; +} diff --git a/src/tools/clippy/tests/ui/cast_size.32bit.stderr b/src/tools/clippy/tests/ui/cast_size.32bit.stderr index cb1620e36a2..5811cb3607b 100644 --- a/src/tools/clippy/tests/ui/cast_size.32bit.stderr +++ b/src/tools/clippy/tests/ui/cast_size.32bit.stderr @@ -177,6 +177,14 @@ error: casting `usize` to `f64` causes a loss of precision on targets with 64-bi LL | 9_999_999_999_999_999usize as f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: casting `usize` to `u16` may truncate the value + --> tests/ui/cast_size.rs:71:20 + | +LL | const N: u16 = M as u16; + | ^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... + error: literal out of range for `usize` --> tests/ui/cast_size.rs:63:5 | @@ -186,5 +194,5 @@ LL | 9_999_999_999_999_999usize as f64; = note: the literal `9_999_999_999_999_999usize` does not fit into the type `usize` whose range is `0..=4294967295` = note: `#[deny(overflowing_literals)]` on by default -error: aborting due to 19 previous errors +error: aborting due to 20 previous errors diff --git a/src/tools/clippy/tests/ui/cast_size.64bit.stderr b/src/tools/clippy/tests/ui/cast_size.64bit.stderr index b6000a52abb..ba1419583ae 100644 --- a/src/tools/clippy/tests/ui/cast_size.64bit.stderr +++ b/src/tools/clippy/tests/ui/cast_size.64bit.stderr @@ -177,5 +177,13 @@ error: casting `usize` to `f64` causes a loss of precision on targets with 64-bi LL | 9_999_999_999_999_999usize as f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 18 previous errors +error: casting `usize` to `u16` may truncate the value + --> tests/ui/cast_size.rs:71:20 + | +LL | const N: u16 = M as u16; + | ^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... + +error: aborting due to 19 previous errors diff --git a/src/tools/clippy/tests/ui/cast_size.rs b/src/tools/clippy/tests/ui/cast_size.rs index e5bef2a99d5..ecc58669419 100644 --- a/src/tools/clippy/tests/ui/cast_size.rs +++ b/src/tools/clippy/tests/ui/cast_size.rs @@ -65,3 +65,9 @@ fn main() { //~[32bit]^^ ERROR: literal out of range for `usize` // 999_999_999_999_999_999_999_999_999_999u128 as f128; } + +fn issue15163() { + const M: usize = 100; + const N: u16 = M as u16; + //~^ cast_possible_truncation +} diff --git a/src/tools/clippy/tests/ui/coerce_container_to_any.fixed b/src/tools/clippy/tests/ui/coerce_container_to_any.fixed index ae9d3ef9656..b5b3f15b4de 100644 --- a/src/tools/clippy/tests/ui/coerce_container_to_any.fixed +++ b/src/tools/clippy/tests/ui/coerce_container_to_any.fixed @@ -3,7 +3,7 @@ use std::any::Any; fn main() { - let x: Box<dyn Any> = Box::new(()); + let mut x: Box<dyn Any> = Box::new(()); let ref_x = &x; f(&*x); @@ -15,12 +15,23 @@ fn main() { let _: &dyn Any = &*x; //~^ coerce_container_to_any + let _: &dyn Any = &*x; + //~^ coerce_container_to_any + + let _: &mut dyn Any = &mut *x; + //~^ coerce_container_to_any + f(&42); f(&Box::new(())); f(&Box::new(Box::new(()))); + let ref_x = &x; f(&**ref_x); f(&*x); let _: &dyn Any = &*x; + + // https://github.com/rust-lang/rust-clippy/issues/15045 + #[allow(clippy::needless_borrow)] + (&x).downcast_ref::<()>().unwrap(); } fn f(_: &dyn Any) {} diff --git a/src/tools/clippy/tests/ui/coerce_container_to_any.rs b/src/tools/clippy/tests/ui/coerce_container_to_any.rs index 9948bd48e0d..4d6527bb552 100644 --- a/src/tools/clippy/tests/ui/coerce_container_to_any.rs +++ b/src/tools/clippy/tests/ui/coerce_container_to_any.rs @@ -3,7 +3,7 @@ use std::any::Any; fn main() { - let x: Box<dyn Any> = Box::new(()); + let mut x: Box<dyn Any> = Box::new(()); let ref_x = &x; f(&x); @@ -15,12 +15,23 @@ fn main() { let _: &dyn Any = &x; //~^ coerce_container_to_any + let _: &dyn Any = &mut x; + //~^ coerce_container_to_any + + let _: &mut dyn Any = &mut x; + //~^ coerce_container_to_any + f(&42); f(&Box::new(())); f(&Box::new(Box::new(()))); + let ref_x = &x; f(&**ref_x); f(&*x); let _: &dyn Any = &*x; + + // https://github.com/rust-lang/rust-clippy/issues/15045 + #[allow(clippy::needless_borrow)] + (&x).downcast_ref::<()>().unwrap(); } fn f(_: &dyn Any) {} diff --git a/src/tools/clippy/tests/ui/coerce_container_to_any.stderr b/src/tools/clippy/tests/ui/coerce_container_to_any.stderr index 00ab77e0ce0..26389c9186e 100644 --- a/src/tools/clippy/tests/ui/coerce_container_to_any.stderr +++ b/src/tools/clippy/tests/ui/coerce_container_to_any.stderr @@ -19,5 +19,17 @@ error: coercing `&std::boxed::Box<dyn std::any::Any>` to `&dyn Any` LL | let _: &dyn Any = &x; | ^^ help: consider dereferencing: `&*x` -error: aborting due to 3 previous errors +error: coercing `&mut std::boxed::Box<dyn std::any::Any>` to `&dyn Any` + --> tests/ui/coerce_container_to_any.rs:18:23 + | +LL | let _: &dyn Any = &mut x; + | ^^^^^^ help: consider dereferencing: `&*x` + +error: coercing `&mut std::boxed::Box<dyn std::any::Any>` to `&mut dyn Any` + --> tests/ui/coerce_container_to_any.rs:21:27 + | +LL | let _: &mut dyn Any = &mut x; + | ^^^^^^ help: consider dereferencing: `&mut *x` + +error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/disallowed_script_idents.rs b/src/tools/clippy/tests/ui/disallowed_script_idents.rs index 08fd1d9669e..dae380045ae 100644 --- a/src/tools/clippy/tests/ui/disallowed_script_idents.rs +++ b/src/tools/clippy/tests/ui/disallowed_script_idents.rs @@ -15,3 +15,17 @@ fn main() { let カウンタ = 10; //~^ disallowed_script_idents } + +fn issue15116() { + const ÄÖÜ: u8 = 0; + const _ÄÖÜ: u8 = 0; + const Ä_ÖÜ: u8 = 0; + const ÄÖ_Ü: u8 = 0; + const ÄÖÜ_: u8 = 0; + let äöüß = 1; + let _äöüß = 1; + let ä_öüß = 1; + let äö_üß = 1; + let äöü_ß = 1; + let äöüß_ = 1; +} diff --git a/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.fixed b/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.fixed index 065f4486e39..5c57c58fbc0 100644 --- a/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.fixed +++ b/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.fixed @@ -72,8 +72,6 @@ pub struct NotEmptyTight; /// ## Heading /// -/// - [x][] - Done -//~^ ERROR: link reference defined in list item -/// - [ ][] - Not Done -//~^ ERROR: link reference defined in list item +/// - [x] - Done +/// - [ ] - Not Done pub struct GithubCheckboxes; diff --git a/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.rs b/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.rs index c7eab50c8b3..06b6ba49e19 100644 --- a/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.rs +++ b/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.rs @@ -73,7 +73,5 @@ pub struct NotEmptyTight; /// ## Heading /// /// - [x] - Done -//~^ ERROR: link reference defined in list item /// - [ ] - Not Done -//~^ ERROR: link reference defined in list item pub struct GithubCheckboxes; diff --git a/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.stderr b/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.stderr index 5a815dabf4d..27314c7e968 100644 --- a/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.stderr +++ b/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.stderr @@ -144,29 +144,5 @@ help: for an intra-doc link, add `[]` between the label and the colon LL | /// - [link][]: def "title" | ++ -error: link reference defined in list item - --> tests/ui/doc/doc_nested_refdef_list_item.rs:75:7 - | -LL | /// - [x] - Done - | ^^^ - | - = help: link definitions are not shown in rendered documentation -help: for an intra-doc link, add `[]` between the label and the colon - | -LL | /// - [x][] - Done - | ++ - -error: link reference defined in list item - --> tests/ui/doc/doc_nested_refdef_list_item.rs:77:7 - | -LL | /// - [ ] - Not Done - | ^^^ - | - = help: link definitions are not shown in rendered documentation -help: for an intra-doc link, add `[]` between the label and the colon - | -LL | /// - [ ][] - Not Done - | ++ - -error: aborting due to 14 previous errors +error: aborting due to 12 previous errors diff --git a/src/tools/clippy/tests/ui/empty_loop_intrinsic.rs b/src/tools/clippy/tests/ui/empty_loop_intrinsic.rs new file mode 100644 index 00000000000..a550e560965 --- /dev/null +++ b/src/tools/clippy/tests/ui/empty_loop_intrinsic.rs @@ -0,0 +1,13 @@ +//@check-pass + +#![warn(clippy::empty_loop)] +#![feature(intrinsics)] +#![feature(rustc_attrs)] + +// From issue #15200 +#[rustc_intrinsic] +#[rustc_nounwind] +/// # Safety +pub const unsafe fn simd_insert<T, U>(x: T, idx: u32, val: U) -> T; + +fn main() {} diff --git a/src/tools/clippy/tests/ui/exit1_compile_flag_test.rs b/src/tools/clippy/tests/ui/exit1_compile_flag_test.rs new file mode 100644 index 00000000000..9f83ed32533 --- /dev/null +++ b/src/tools/clippy/tests/ui/exit1_compile_flag_test.rs @@ -0,0 +1,17 @@ +//@compile-flags: --test +#![warn(clippy::exit)] + +fn not_main() { + if true { + std::process::exit(4); + //~^ exit + } +} + +fn main() { + if true { + std::process::exit(2); + }; + not_main(); + std::process::exit(1); +} diff --git a/src/tools/clippy/tests/ui/exit1_compile_flag_test.stderr b/src/tools/clippy/tests/ui/exit1_compile_flag_test.stderr new file mode 100644 index 00000000000..6e33c39f0d7 --- /dev/null +++ b/src/tools/clippy/tests/ui/exit1_compile_flag_test.stderr @@ -0,0 +1,11 @@ +error: usage of `process::exit` + --> tests/ui/exit1_compile_flag_test.rs:6:9 + | +LL | std::process::exit(4); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::exit` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::exit)]` + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/exit2_compile_flag_test.rs b/src/tools/clippy/tests/ui/exit2_compile_flag_test.rs new file mode 100644 index 00000000000..0b994ebc56c --- /dev/null +++ b/src/tools/clippy/tests/ui/exit2_compile_flag_test.rs @@ -0,0 +1,15 @@ +//@compile-flags: --test +#![warn(clippy::exit)] + +fn also_not_main() { + std::process::exit(3); + //~^ exit +} + +fn main() { + if true { + std::process::exit(2); + }; + also_not_main(); + std::process::exit(1); +} diff --git a/src/tools/clippy/tests/ui/exit2_compile_flag_test.stderr b/src/tools/clippy/tests/ui/exit2_compile_flag_test.stderr new file mode 100644 index 00000000000..51eb26e9c2a --- /dev/null +++ b/src/tools/clippy/tests/ui/exit2_compile_flag_test.stderr @@ -0,0 +1,11 @@ +error: usage of `process::exit` + --> tests/ui/exit2_compile_flag_test.rs:5:5 + | +LL | std::process::exit(3); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::exit` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::exit)]` + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/exit3_compile_flag_test.rs b/src/tools/clippy/tests/ui/exit3_compile_flag_test.rs new file mode 100644 index 00000000000..f8131ead2da --- /dev/null +++ b/src/tools/clippy/tests/ui/exit3_compile_flag_test.rs @@ -0,0 +1,11 @@ +//@ check-pass +//@compile-flags: --test + +#![warn(clippy::exit)] + +fn main() { + if true { + std::process::exit(2); + }; + std::process::exit(1); +} diff --git a/src/tools/clippy/tests/ui/exit4.rs b/src/tools/clippy/tests/ui/exit4.rs new file mode 100644 index 00000000000..821a26fd78b --- /dev/null +++ b/src/tools/clippy/tests/ui/exit4.rs @@ -0,0 +1,8 @@ +//@ check-pass +//@compile-flags: --test + +#![warn(clippy::exit)] + +fn main() { + std::process::exit(0) +} diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.fixed b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed index 83aeddb2a1f..884bae00432 100644 --- a/src/tools/clippy/tests/ui/floating_point_mul_add.fixed +++ b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed @@ -69,3 +69,47 @@ fn _issue11831() { let _ = a + b * c; } + +fn _issue14897() { + let x = 1.0; + let _ = x * 2.0 + 0.5; // should not suggest mul_add + let _ = 0.5 + x * 2.0; // should not suggest mul_add + let _ = 0.5 + x * 1.2; // should not suggest mul_add + let _ = 1.2 + x * 1.2; // should not suggest mul_add + + let x = -1.0; + let _ = 0.5 + x * 1.2; // should not suggest mul_add + + let x = { 4.0 }; + let _ = 0.5 + x * 1.2; // should not suggest mul_add + + let x = if 1 > 2 { 1.0 } else { 2.0 }; + let _ = 0.5 + x * 1.2; // should not suggest mul_add + + let x = 2.4 + 1.2; + let _ = 0.5 + x * 1.2; // should not suggest mul_add + + let f = || 4.0; + let x = f(); + let _ = 0.5 + f() * 1.2; // should not suggest mul_add + let _ = 0.5 + x * 1.2; // should not suggest mul_add + + let x = 0.1; + let y = x; + let z = y; + let _ = 0.5 + z * 1.2; // should not suggest mul_add + + let _ = 2.0f64.mul_add(x, 0.5); + //~^ suboptimal_flops + let _ = 2.0f64.mul_add(x, 0.5); + //~^ suboptimal_flops + + let _ = 2.0f64.mul_add(4.0, x); + //~^ suboptimal_flops + + let y: f64 = 1.0; + let _ = y.mul_add(2.0, 0.5); + //~^ suboptimal_flops + let _ = 1.0f64.mul_add(2.0, 0.5); + //~^ suboptimal_flops +} diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.rs b/src/tools/clippy/tests/ui/floating_point_mul_add.rs index 039ee8d053f..9ceb2ec9606 100644 --- a/src/tools/clippy/tests/ui/floating_point_mul_add.rs +++ b/src/tools/clippy/tests/ui/floating_point_mul_add.rs @@ -69,3 +69,47 @@ fn _issue11831() { let _ = a + b * c; } + +fn _issue14897() { + let x = 1.0; + let _ = x * 2.0 + 0.5; // should not suggest mul_add + let _ = 0.5 + x * 2.0; // should not suggest mul_add + let _ = 0.5 + x * 1.2; // should not suggest mul_add + let _ = 1.2 + x * 1.2; // should not suggest mul_add + + let x = -1.0; + let _ = 0.5 + x * 1.2; // should not suggest mul_add + + let x = { 4.0 }; + let _ = 0.5 + x * 1.2; // should not suggest mul_add + + let x = if 1 > 2 { 1.0 } else { 2.0 }; + let _ = 0.5 + x * 1.2; // should not suggest mul_add + + let x = 2.4 + 1.2; + let _ = 0.5 + x * 1.2; // should not suggest mul_add + + let f = || 4.0; + let x = f(); + let _ = 0.5 + f() * 1.2; // should not suggest mul_add + let _ = 0.5 + x * 1.2; // should not suggest mul_add + + let x = 0.1; + let y = x; + let z = y; + let _ = 0.5 + z * 1.2; // should not suggest mul_add + + let _ = 0.5 + 2.0 * x; + //~^ suboptimal_flops + let _ = 2.0 * x + 0.5; + //~^ suboptimal_flops + + let _ = x + 2.0 * 4.0; + //~^ suboptimal_flops + + let y: f64 = 1.0; + let _ = y * 2.0 + 0.5; + //~^ suboptimal_flops + let _ = 1.0 * 2.0 + 0.5; + //~^ suboptimal_flops +} diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.stderr b/src/tools/clippy/tests/ui/floating_point_mul_add.stderr index 6482127bcc0..dad65ddf2ec 100644 --- a/src/tools/clippy/tests/ui/floating_point_mul_add.stderr +++ b/src/tools/clippy/tests/ui/floating_point_mul_add.stderr @@ -79,5 +79,35 @@ error: multiply and add expressions can be calculated more efficiently and accur LL | let _ = a - (b * u as f64); | ^^^^^^^^^^^^^^^^^^ help: consider using: `b.mul_add(-(u as f64), a)` -error: aborting due to 13 previous errors +error: multiply and add expressions can be calculated more efficiently and accurately + --> tests/ui/floating_point_mul_add.rs:102:13 + | +LL | let _ = 0.5 + 2.0 * x; + | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(x, 0.5)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> tests/ui/floating_point_mul_add.rs:104:13 + | +LL | let _ = 2.0 * x + 0.5; + | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(x, 0.5)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> tests/ui/floating_point_mul_add.rs:107:13 + | +LL | let _ = x + 2.0 * 4.0; + | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4.0, x)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> tests/ui/floating_point_mul_add.rs:111:13 + | +LL | let _ = y * 2.0 + 0.5; + | ^^^^^^^^^^^^^ help: consider using: `y.mul_add(2.0, 0.5)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> tests/ui/floating_point_mul_add.rs:113:13 + | +LL | let _ = 1.0 * 2.0 + 0.5; + | ^^^^^^^^^^^^^^^ help: consider using: `1.0f64.mul_add(2.0, 0.5)` + +error: aborting due to 18 previous errors diff --git a/src/tools/clippy/tests/ui/manual_is_variant_and.fixed b/src/tools/clippy/tests/ui/manual_is_variant_and.fixed index 6425f32c09c..65a9cfa6e64 100644 --- a/src/tools/clippy/tests/ui/manual_is_variant_and.fixed +++ b/src/tools/clippy/tests/ui/manual_is_variant_and.fixed @@ -61,7 +61,7 @@ fn option_methods() { let _ = Some(2).is_some_and(|x| x % 2 == 0); //~^ manual_is_variant_and - let _ = Some(2).is_none_or(|x| x % 2 == 0); + let _ = Some(2).is_none_or(|x| x % 2 != 0); //~^ manual_is_variant_and let _ = Some(2).is_some_and(|x| x % 2 == 0); //~^ manual_is_variant_and @@ -116,3 +116,113 @@ fn main() { option_methods(); result_methods(); } + +fn issue15202() { + let xs = [None, Some(b'_'), Some(b'1')]; + for x in xs { + let a1 = x.is_none_or(|b| !b.is_ascii_digit()); + //~^ manual_is_variant_and + let a2 = x.is_none_or(|b| !b.is_ascii_digit()); + assert_eq!(a1, a2); + } + + for x in xs { + let a1 = x.is_none_or(|b| b.is_ascii_digit()); + //~^ manual_is_variant_and + let a2 = x.is_none_or(|b| b.is_ascii_digit()); + assert_eq!(a1, a2); + } + + for x in xs { + let a1 = x.is_some_and(|b| b.is_ascii_digit()); + //~^ manual_is_variant_and + let a2 = x.is_some_and(|b| b.is_ascii_digit()); + assert_eq!(a1, a2); + } + + for x in xs { + let a1 = x.is_some_and(|b| !b.is_ascii_digit()); + //~^ manual_is_variant_and + let a2 = x.is_some_and(|b| !b.is_ascii_digit()); + assert_eq!(a1, a2); + } + + let xs = [Err("foo"), Ok(b'_'), Ok(b'1')]; + for x in xs { + let a1 = !x.is_ok_and(|b| b.is_ascii_digit()); + //~^ manual_is_variant_and + let a2 = !x.is_ok_and(|b| b.is_ascii_digit()); + assert_eq!(a1, a2); + } + + for x in xs { + let a1 = !x.is_ok_and(|b| !b.is_ascii_digit()); + //~^ manual_is_variant_and + let a2 = !x.is_ok_and(|b| !b.is_ascii_digit()); + assert_eq!(a1, a2); + } + + for x in xs { + let a1 = x.is_ok_and(|b| b.is_ascii_digit()); + //~^ manual_is_variant_and + let a2 = x.is_ok_and(|b| b.is_ascii_digit()); + assert_eq!(a1, a2); + } + + for x in xs { + let a1 = x.is_ok_and(|b| !b.is_ascii_digit()); + //~^ manual_is_variant_and + let a2 = x.is_ok_and(|b| !b.is_ascii_digit()); + assert_eq!(a1, a2); + } +} + +mod with_func { + fn iad(b: u8) -> bool { + b.is_ascii_digit() + } + + fn check_option(b: Option<u8>) { + let a1 = b.is_some_and(iad); + //~^ manual_is_variant_and + let a2 = b.is_some_and(iad); + assert_eq!(a1, a2); + + let a1 = b.is_some_and(|x| !iad(x)); + //~^ manual_is_variant_and + let a2 = b.is_some_and(|x| !iad(x)); + assert_eq!(a1, a2); + + let a1 = b.is_none_or(|x| !iad(x)); + //~^ manual_is_variant_and + let a2 = b.is_none_or(|x| !iad(x)); + assert_eq!(a1, a2); + + let a1 = b.is_none_or(iad); + //~^ manual_is_variant_and + let a2 = b.is_none_or(iad); + assert_eq!(a1, a2); + } + + fn check_result(b: Result<u8, ()>) { + let a1 = b.is_ok_and(iad); + //~^ manual_is_variant_and + let a2 = b.is_ok_and(iad); + assert_eq!(a1, a2); + + let a1 = b.is_ok_and(|x| !iad(x)); + //~^ manual_is_variant_and + let a2 = b.is_ok_and(|x| !iad(x)); + assert_eq!(a1, a2); + + let a1 = !b.is_ok_and(iad); + //~^ manual_is_variant_and + let a2 = !b.is_ok_and(iad); + assert_eq!(a1, a2); + + let a1 = !b.is_ok_and(|x| !iad(x)); + //~^ manual_is_variant_and + let a2 = !b.is_ok_and(|x| !iad(x)); + assert_eq!(a1, a2); + } +} diff --git a/src/tools/clippy/tests/ui/manual_is_variant_and.rs b/src/tools/clippy/tests/ui/manual_is_variant_and.rs index e069e97a04d..85b45d654a7 100644 --- a/src/tools/clippy/tests/ui/manual_is_variant_and.rs +++ b/src/tools/clippy/tests/ui/manual_is_variant_and.rs @@ -125,3 +125,113 @@ fn main() { option_methods(); result_methods(); } + +fn issue15202() { + let xs = [None, Some(b'_'), Some(b'1')]; + for x in xs { + let a1 = x.map(|b| b.is_ascii_digit()) != Some(true); + //~^ manual_is_variant_and + let a2 = x.is_none_or(|b| !b.is_ascii_digit()); + assert_eq!(a1, a2); + } + + for x in xs { + let a1 = x.map(|b| b.is_ascii_digit()) != Some(false); + //~^ manual_is_variant_and + let a2 = x.is_none_or(|b| b.is_ascii_digit()); + assert_eq!(a1, a2); + } + + for x in xs { + let a1 = x.map(|b| b.is_ascii_digit()) == Some(true); + //~^ manual_is_variant_and + let a2 = x.is_some_and(|b| b.is_ascii_digit()); + assert_eq!(a1, a2); + } + + for x in xs { + let a1 = x.map(|b| b.is_ascii_digit()) == Some(false); + //~^ manual_is_variant_and + let a2 = x.is_some_and(|b| !b.is_ascii_digit()); + assert_eq!(a1, a2); + } + + let xs = [Err("foo"), Ok(b'_'), Ok(b'1')]; + for x in xs { + let a1 = x.map(|b| b.is_ascii_digit()) != Ok(true); + //~^ manual_is_variant_and + let a2 = !x.is_ok_and(|b| b.is_ascii_digit()); + assert_eq!(a1, a2); + } + + for x in xs { + let a1 = x.map(|b| b.is_ascii_digit()) != Ok(false); + //~^ manual_is_variant_and + let a2 = !x.is_ok_and(|b| !b.is_ascii_digit()); + assert_eq!(a1, a2); + } + + for x in xs { + let a1 = x.map(|b| b.is_ascii_digit()) == Ok(true); + //~^ manual_is_variant_and + let a2 = x.is_ok_and(|b| b.is_ascii_digit()); + assert_eq!(a1, a2); + } + + for x in xs { + let a1 = x.map(|b| b.is_ascii_digit()) == Ok(false); + //~^ manual_is_variant_and + let a2 = x.is_ok_and(|b| !b.is_ascii_digit()); + assert_eq!(a1, a2); + } +} + +mod with_func { + fn iad(b: u8) -> bool { + b.is_ascii_digit() + } + + fn check_option(b: Option<u8>) { + let a1 = b.map(iad) == Some(true); + //~^ manual_is_variant_and + let a2 = b.is_some_and(iad); + assert_eq!(a1, a2); + + let a1 = b.map(iad) == Some(false); + //~^ manual_is_variant_and + let a2 = b.is_some_and(|x| !iad(x)); + assert_eq!(a1, a2); + + let a1 = b.map(iad) != Some(true); + //~^ manual_is_variant_and + let a2 = b.is_none_or(|x| !iad(x)); + assert_eq!(a1, a2); + + let a1 = b.map(iad) != Some(false); + //~^ manual_is_variant_and + let a2 = b.is_none_or(iad); + assert_eq!(a1, a2); + } + + fn check_result(b: Result<u8, ()>) { + let a1 = b.map(iad) == Ok(true); + //~^ manual_is_variant_and + let a2 = b.is_ok_and(iad); + assert_eq!(a1, a2); + + let a1 = b.map(iad) == Ok(false); + //~^ manual_is_variant_and + let a2 = b.is_ok_and(|x| !iad(x)); + assert_eq!(a1, a2); + + let a1 = b.map(iad) != Ok(true); + //~^ manual_is_variant_and + let a2 = !b.is_ok_and(iad); + assert_eq!(a1, a2); + + let a1 = b.map(iad) != Ok(false); + //~^ manual_is_variant_and + let a2 = !b.is_ok_and(|x| !iad(x)); + assert_eq!(a1, a2); + } +} diff --git a/src/tools/clippy/tests/ui/manual_is_variant_and.stderr b/src/tools/clippy/tests/ui/manual_is_variant_and.stderr index f770319a268..da36b5a07d2 100644 --- a/src/tools/clippy/tests/ui/manual_is_variant_and.stderr +++ b/src/tools/clippy/tests/ui/manual_is_variant_and.stderr @@ -54,7 +54,7 @@ error: called `.map() != Some()` --> tests/ui/manual_is_variant_and.rs:70:13 | LL | let _ = Some(2).map(|x| x % 2 == 0) != Some(true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Some(2).is_none_or(|x| x % 2 == 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Some(2).is_none_or(|x| x % 2 != 0)` error: called `.map() == Some()` --> tests/ui/manual_is_variant_and.rs:72:13 @@ -126,5 +126,101 @@ error: called `map(<f>).unwrap_or_default()` on a `Result` value LL | let _ = res2.map(char::is_alphanumeric).unwrap_or_default(); // should lint | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_ok_and(char::is_alphanumeric)` -error: aborting due to 15 previous errors +error: called `.map() != Some()` + --> tests/ui/manual_is_variant_and.rs:132:18 + | +LL | let a1 = x.map(|b| b.is_ascii_digit()) != Some(true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.is_none_or(|b| !b.is_ascii_digit())` + +error: called `.map() != Some()` + --> tests/ui/manual_is_variant_and.rs:139:18 + | +LL | let a1 = x.map(|b| b.is_ascii_digit()) != Some(false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.is_none_or(|b| b.is_ascii_digit())` + +error: called `.map() == Some()` + --> tests/ui/manual_is_variant_and.rs:146:18 + | +LL | let a1 = x.map(|b| b.is_ascii_digit()) == Some(true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.is_some_and(|b| b.is_ascii_digit())` + +error: called `.map() == Some()` + --> tests/ui/manual_is_variant_and.rs:153:18 + | +LL | let a1 = x.map(|b| b.is_ascii_digit()) == Some(false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.is_some_and(|b| !b.is_ascii_digit())` + +error: called `.map() != Ok()` + --> tests/ui/manual_is_variant_and.rs:161:18 + | +LL | let a1 = x.map(|b| b.is_ascii_digit()) != Ok(true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!x.is_ok_and(|b| b.is_ascii_digit())` + +error: called `.map() != Ok()` + --> tests/ui/manual_is_variant_and.rs:168:18 + | +LL | let a1 = x.map(|b| b.is_ascii_digit()) != Ok(false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!x.is_ok_and(|b| !b.is_ascii_digit())` + +error: called `.map() == Ok()` + --> tests/ui/manual_is_variant_and.rs:175:18 + | +LL | let a1 = x.map(|b| b.is_ascii_digit()) == Ok(true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.is_ok_and(|b| b.is_ascii_digit())` + +error: called `.map() == Ok()` + --> tests/ui/manual_is_variant_and.rs:182:18 + | +LL | let a1 = x.map(|b| b.is_ascii_digit()) == Ok(false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.is_ok_and(|b| !b.is_ascii_digit())` + +error: called `.map() == Some()` + --> tests/ui/manual_is_variant_and.rs:195:18 + | +LL | let a1 = b.map(iad) == Some(true); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `b.is_some_and(iad)` + +error: called `.map() == Some()` + --> tests/ui/manual_is_variant_and.rs:200:18 + | +LL | let a1 = b.map(iad) == Some(false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `b.is_some_and(|x| !iad(x))` + +error: called `.map() != Some()` + --> tests/ui/manual_is_variant_and.rs:205:18 + | +LL | let a1 = b.map(iad) != Some(true); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `b.is_none_or(|x| !iad(x))` + +error: called `.map() != Some()` + --> tests/ui/manual_is_variant_and.rs:210:18 + | +LL | let a1 = b.map(iad) != Some(false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `b.is_none_or(iad)` + +error: called `.map() == Ok()` + --> tests/ui/manual_is_variant_and.rs:217:18 + | +LL | let a1 = b.map(iad) == Ok(true); + | ^^^^^^^^^^^^^^^^^^^^^^ help: use: `b.is_ok_and(iad)` + +error: called `.map() == Ok()` + --> tests/ui/manual_is_variant_and.rs:222:18 + | +LL | let a1 = b.map(iad) == Ok(false); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use: `b.is_ok_and(|x| !iad(x))` + +error: called `.map() != Ok()` + --> tests/ui/manual_is_variant_and.rs:227:18 + | +LL | let a1 = b.map(iad) != Ok(true); + | ^^^^^^^^^^^^^^^^^^^^^^ help: use: `!b.is_ok_and(iad)` + +error: called `.map() != Ok()` + --> tests/ui/manual_is_variant_and.rs:232:18 + | +LL | let a1 = b.map(iad) != Ok(false); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!b.is_ok_and(|x| !iad(x))` + +error: aborting due to 31 previous errors diff --git a/src/tools/clippy/tests/ui/manual_let_else_match.fixed b/src/tools/clippy/tests/ui/manual_let_else_match.fixed index 588ba5edd8f..15f604aec29 100644 --- a/src/tools/clippy/tests/ui/manual_let_else_match.fixed +++ b/src/tools/clippy/tests/ui/manual_let_else_match.fixed @@ -137,3 +137,48 @@ fn not_fire() { fn issue11579() { let Some(msg) = Some("hi") else { unreachable!("can't happen") }; } + +#[derive(Clone, Copy)] +struct Issue9939<T> { + avalanche: T, +} + +fn issue9939() { + let issue = Some(Issue9939 { avalanche: 1 }); + let Some(Issue9939 { avalanche: tornado }) = issue else { unreachable!("can't happen") }; + let issue = Some(Issue9939 { avalanche: true }); + let Some(Issue9939 { avalanche: acid_rain }) = issue else { unreachable!("can't happen") }; + assert_eq!(tornado, 1); + assert!(acid_rain); + + // without shadowing + let _x @ Some(Issue9939 { avalanche: _y }) = issue else { unreachable!("can't happen") }; + + // with shadowing + let Some(Issue9939 { avalanche: _x }) = issue else { unreachable!("can't happen") }; +} + +#[derive(Clone, Copy)] +struct Issue9939b<T, U> { + earthquake: T, + hurricane: U, +} + +fn issue9939b() { + let issue = Some(Issue9939b { + earthquake: true, + hurricane: 1, + }); + let issue @ Some(Issue9939b { earthquake: flood, hurricane: drought }) = issue else { unreachable!("can't happen") }; + assert_eq!(drought, 1); + assert!(flood); + assert!(issue.is_some()); + + // without shadowing + let _x @ Some(Issue9939b { earthquake: erosion, hurricane: _y }) = issue else { unreachable!("can't happen") }; + assert!(erosion); + + // with shadowing + let Some(Issue9939b { earthquake: erosion, hurricane: _x }) = issue else { unreachable!("can't happen") }; + assert!(erosion); +} diff --git a/src/tools/clippy/tests/ui/manual_let_else_match.rs b/src/tools/clippy/tests/ui/manual_let_else_match.rs index 6416753bac1..44a044b142b 100644 --- a/src/tools/clippy/tests/ui/manual_let_else_match.rs +++ b/src/tools/clippy/tests/ui/manual_let_else_match.rs @@ -177,3 +177,76 @@ fn issue11579() { _ => unreachable!("can't happen"), }; } + +#[derive(Clone, Copy)] +struct Issue9939<T> { + avalanche: T, +} + +fn issue9939() { + let issue = Some(Issue9939 { avalanche: 1 }); + let tornado = match issue { + //~^ manual_let_else + Some(Issue9939 { avalanche }) => avalanche, + _ => unreachable!("can't happen"), + }; + let issue = Some(Issue9939 { avalanche: true }); + let acid_rain = match issue { + //~^ manual_let_else + Some(Issue9939 { avalanche: tornado }) => tornado, + _ => unreachable!("can't happen"), + }; + assert_eq!(tornado, 1); + assert!(acid_rain); + + // without shadowing + let _y = match issue { + //~^ manual_let_else + _x @ Some(Issue9939 { avalanche }) => avalanche, + None => unreachable!("can't happen"), + }; + + // with shadowing + let _x = match issue { + //~^ manual_let_else + _x @ Some(Issue9939 { avalanche }) => avalanche, + None => unreachable!("can't happen"), + }; +} + +#[derive(Clone, Copy)] +struct Issue9939b<T, U> { + earthquake: T, + hurricane: U, +} + +fn issue9939b() { + let issue = Some(Issue9939b { + earthquake: true, + hurricane: 1, + }); + let (issue, drought, flood) = match issue { + //~^ manual_let_else + flood @ Some(Issue9939b { earthquake, hurricane }) => (flood, hurricane, earthquake), + None => unreachable!("can't happen"), + }; + assert_eq!(drought, 1); + assert!(flood); + assert!(issue.is_some()); + + // without shadowing + let (_y, erosion) = match issue { + //~^ manual_let_else + _x @ Some(Issue9939b { earthquake, hurricane }) => (hurricane, earthquake), + None => unreachable!("can't happen"), + }; + assert!(erosion); + + // with shadowing + let (_x, erosion) = match issue { + //~^ manual_let_else + _x @ Some(Issue9939b { earthquake, hurricane }) => (hurricane, earthquake), + None => unreachable!("can't happen"), + }; + assert!(erosion); +} diff --git a/src/tools/clippy/tests/ui/manual_let_else_match.stderr b/src/tools/clippy/tests/ui/manual_let_else_match.stderr index 393562c629b..ed6117ebffb 100644 --- a/src/tools/clippy/tests/ui/manual_let_else_match.stderr +++ b/src/tools/clippy/tests/ui/manual_let_else_match.stderr @@ -101,5 +101,75 @@ LL | | _ => unreachable!("can't happen"), LL | | }; | |______^ help: consider writing: `let Some(msg) = Some("hi") else { unreachable!("can't happen") };` -error: aborting due to 10 previous errors +error: this could be rewritten as `let...else` + --> tests/ui/manual_let_else_match.rs:188:5 + | +LL | / let tornado = match issue { +LL | | +LL | | Some(Issue9939 { avalanche }) => avalanche, +LL | | _ => unreachable!("can't happen"), +LL | | }; + | |______^ help: consider writing: `let Some(Issue9939 { avalanche: tornado }) = issue else { unreachable!("can't happen") };` + +error: this could be rewritten as `let...else` + --> tests/ui/manual_let_else_match.rs:194:5 + | +LL | / let acid_rain = match issue { +LL | | +LL | | Some(Issue9939 { avalanche: tornado }) => tornado, +LL | | _ => unreachable!("can't happen"), +LL | | }; + | |______^ help: consider writing: `let Some(Issue9939 { avalanche: acid_rain }) = issue else { unreachable!("can't happen") };` + +error: this could be rewritten as `let...else` + --> tests/ui/manual_let_else_match.rs:203:5 + | +LL | / let _y = match issue { +LL | | +LL | | _x @ Some(Issue9939 { avalanche }) => avalanche, +LL | | None => unreachable!("can't happen"), +LL | | }; + | |______^ help: consider writing: `let _x @ Some(Issue9939 { avalanche: _y }) = issue else { unreachable!("can't happen") };` + +error: this could be rewritten as `let...else` + --> tests/ui/manual_let_else_match.rs:210:5 + | +LL | / let _x = match issue { +LL | | +LL | | _x @ Some(Issue9939 { avalanche }) => avalanche, +LL | | None => unreachable!("can't happen"), +LL | | }; + | |______^ help: consider writing: `let Some(Issue9939 { avalanche: _x }) = issue else { unreachable!("can't happen") };` + +error: this could be rewritten as `let...else` + --> tests/ui/manual_let_else_match.rs:228:5 + | +LL | / let (issue, drought, flood) = match issue { +LL | | +LL | | flood @ Some(Issue9939b { earthquake, hurricane }) => (flood, hurricane, earthquake), +LL | | None => unreachable!("can't happen"), +LL | | }; + | |______^ help: consider writing: `let issue @ Some(Issue9939b { earthquake: flood, hurricane: drought }) = issue else { unreachable!("can't happen") };` + +error: this could be rewritten as `let...else` + --> tests/ui/manual_let_else_match.rs:238:5 + | +LL | / let (_y, erosion) = match issue { +LL | | +LL | | _x @ Some(Issue9939b { earthquake, hurricane }) => (hurricane, earthquake), +LL | | None => unreachable!("can't happen"), +LL | | }; + | |______^ help: consider writing: `let _x @ Some(Issue9939b { earthquake: erosion, hurricane: _y }) = issue else { unreachable!("can't happen") };` + +error: this could be rewritten as `let...else` + --> tests/ui/manual_let_else_match.rs:246:5 + | +LL | / let (_x, erosion) = match issue { +LL | | +LL | | _x @ Some(Issue9939b { earthquake, hurricane }) => (hurricane, earthquake), +LL | | None => unreachable!("can't happen"), +LL | | }; + | |______^ help: consider writing: `let Some(Issue9939b { earthquake: erosion, hurricane: _x }) = issue else { unreachable!("can't happen") };` + +error: aborting due to 17 previous errors diff --git a/src/tools/clippy/tests/ui/missing_panics_doc.rs b/src/tools/clippy/tests/ui/missing_panics_doc.rs index ffdae8504f7..d016e099e30 100644 --- a/src/tools/clippy/tests/ui/missing_panics_doc.rs +++ b/src/tools/clippy/tests/ui/missing_panics_doc.rs @@ -250,3 +250,31 @@ pub fn issue_12760<const N: usize>() { } } } + +/// This needs documenting +pub fn unwrap_expect_etc_in_const() { + let a = const { std::num::NonZeroUsize::new(1).unwrap() }; + // This should still pass the lint even if it is guaranteed to panic at compile-time + let b = const { std::num::NonZeroUsize::new(0).unwrap() }; +} + +/// This needs documenting +pub const fn unwrap_expect_etc_in_const_fn_fails() { + //~^ missing_panics_doc + let a = std::num::NonZeroUsize::new(1).unwrap(); +} + +/// This needs documenting +pub const fn assert_in_const_fn_fails() { + //~^ missing_panics_doc + let x = 0; + if x == 0 { + panic!(); + } +} + +/// This needs documenting +pub const fn in_const_fn<const N: usize>(n: usize) { + //~^ missing_panics_doc + assert!(N > n); +} diff --git a/src/tools/clippy/tests/ui/missing_panics_doc.stderr b/src/tools/clippy/tests/ui/missing_panics_doc.stderr index 7f0acf8de9b..85a00914427 100644 --- a/src/tools/clippy/tests/ui/missing_panics_doc.stderr +++ b/src/tools/clippy/tests/ui/missing_panics_doc.stderr @@ -180,5 +180,41 @@ note: first possible panic found here LL | *v.last().expect("passed an empty thing") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 15 previous errors +error: docs for function which may panic missing `# Panics` section + --> tests/ui/missing_panics_doc.rs:262:1 + | +LL | pub const fn unwrap_expect_etc_in_const_fn_fails() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> tests/ui/missing_panics_doc.rs:264:13 + | +LL | let a = std::num::NonZeroUsize::new(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: docs for function which may panic missing `# Panics` section + --> tests/ui/missing_panics_doc.rs:268:1 + | +LL | pub const fn assert_in_const_fn_fails() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> tests/ui/missing_panics_doc.rs:272:9 + | +LL | panic!(); + | ^^^^^^^^ + +error: docs for function which may panic missing `# Panics` section + --> tests/ui/missing_panics_doc.rs:277:1 + | +LL | pub const fn in_const_fn<const N: usize>(n: usize) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> tests/ui/missing_panics_doc.rs:279:5 + | +LL | assert!(N > n); + | ^^^^^^^^^^^^^^ + +error: aborting due to 18 previous errors diff --git a/src/tools/clippy/tests/ui/needless_bool_assign.fixed b/src/tools/clippy/tests/ui/needless_bool_assign.fixed index e0c717ecda2..d6fab4c51b5 100644 --- a/src/tools/clippy/tests/ui/needless_bool_assign.fixed +++ b/src/tools/clippy/tests/ui/needless_bool_assign.fixed @@ -33,3 +33,12 @@ fn main() { b = true; } } + +fn issue15063(x: bool, y: bool) { + let mut z = false; + + if x && y { + todo!() + } else { z = x || y; } + //~^^^^^ needless_bool_assign +} diff --git a/src/tools/clippy/tests/ui/needless_bool_assign.rs b/src/tools/clippy/tests/ui/needless_bool_assign.rs index 3e4fecefa78..c504f61f4dd 100644 --- a/src/tools/clippy/tests/ui/needless_bool_assign.rs +++ b/src/tools/clippy/tests/ui/needless_bool_assign.rs @@ -45,3 +45,16 @@ fn main() { b = true; } } + +fn issue15063(x: bool, y: bool) { + let mut z = false; + + if x && y { + todo!() + } else if x || y { + z = true; + } else { + z = false; + } + //~^^^^^ needless_bool_assign +} diff --git a/src/tools/clippy/tests/ui/needless_bool_assign.stderr b/src/tools/clippy/tests/ui/needless_bool_assign.stderr index f33a4bc0c59..1d09b8b25a0 100644 --- a/src/tools/clippy/tests/ui/needless_bool_assign.stderr +++ b/src/tools/clippy/tests/ui/needless_bool_assign.stderr @@ -51,5 +51,16 @@ LL | | } = note: `-D clippy::if-same-then-else` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::if_same_then_else)]` -error: aborting due to 4 previous errors +error: this if-then-else expression assigns a bool literal + --> tests/ui/needless_bool_assign.rs:54:12 + | +LL | } else if x || y { + | ____________^ +LL | | z = true; +LL | | } else { +LL | | z = false; +LL | | } + | |_____^ help: you can reduce it to: `{ z = x || y; }` + +error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/neg_multiply.fixed b/src/tools/clippy/tests/ui/neg_multiply.fixed index ff6e08300e2..32d466e88fc 100644 --- a/src/tools/clippy/tests/ui/neg_multiply.fixed +++ b/src/tools/clippy/tests/ui/neg_multiply.fixed @@ -82,3 +82,15 @@ fn float() { -1.0 * -1.0; // should be ok } + +struct Y { + delta: f64, +} + +fn nested() { + let a = Y { delta: 1.0 }; + let b = Y { delta: 1.0 }; + let _ = (-(a.delta - 0.5).abs()).total_cmp(&1.0); + //~^ neg_multiply + let _ = (-(a.delta - 0.5).abs()).total_cmp(&1.0); +} diff --git a/src/tools/clippy/tests/ui/neg_multiply.rs b/src/tools/clippy/tests/ui/neg_multiply.rs index b0f4e85c78e..241a72c6d99 100644 --- a/src/tools/clippy/tests/ui/neg_multiply.rs +++ b/src/tools/clippy/tests/ui/neg_multiply.rs @@ -82,3 +82,15 @@ fn float() { -1.0 * -1.0; // should be ok } + +struct Y { + delta: f64, +} + +fn nested() { + let a = Y { delta: 1.0 }; + let b = Y { delta: 1.0 }; + let _ = ((a.delta - 0.5).abs() * -1.0).total_cmp(&1.0); + //~^ neg_multiply + let _ = (-(a.delta - 0.5).abs()).total_cmp(&1.0); +} diff --git a/src/tools/clippy/tests/ui/neg_multiply.stderr b/src/tools/clippy/tests/ui/neg_multiply.stderr index 2ef7e32ce05..f4fb6d3ce54 100644 --- a/src/tools/clippy/tests/ui/neg_multiply.stderr +++ b/src/tools/clippy/tests/ui/neg_multiply.stderr @@ -97,5 +97,11 @@ error: this multiplication by -1 can be written more succinctly LL | (3.0_f32 as f64) * -1.0; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `-(3.0_f32 as f64)` -error: aborting due to 16 previous errors +error: this multiplication by -1 can be written more succinctly + --> tests/ui/neg_multiply.rs:93:13 + | +LL | let _ = ((a.delta - 0.5).abs() * -1.0).total_cmp(&1.0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-(a.delta - 0.5).abs())` + +error: aborting due to 17 previous errors diff --git a/src/tools/clippy/tests/ui/op_ref.fixed b/src/tools/clippy/tests/ui/op_ref.fixed index f412190b9fd..4bf4b91888c 100644 --- a/src/tools/clippy/tests/ui/op_ref.fixed +++ b/src/tools/clippy/tests/ui/op_ref.fixed @@ -110,3 +110,37 @@ mod issue_2597 { &array[idx] < val } } + +#[allow(clippy::needless_if)] +fn issue15063() { + use std::ops::BitAnd; + + macro_rules! mac { + ($e:expr) => { + $e.clone() + }; + } + + let x = 1; + if x == mac!(1) {} + //~^ op_ref + + #[derive(Copy, Clone)] + struct Y(i32); + impl BitAnd for Y { + type Output = Y; + fn bitand(self, rhs: Y) -> Y { + Y(self.0 & rhs.0) + } + } + impl<'a> BitAnd<&'a Y> for Y { + type Output = Y; + fn bitand(self, rhs: &'a Y) -> Y { + Y(self.0 & rhs.0) + } + } + let x = Y(1); + let y = Y(2); + let z = x & mac!(y); + //~^ op_ref +} diff --git a/src/tools/clippy/tests/ui/op_ref.rs b/src/tools/clippy/tests/ui/op_ref.rs index a4bbd86c7e9..9a192661aaf 100644 --- a/src/tools/clippy/tests/ui/op_ref.rs +++ b/src/tools/clippy/tests/ui/op_ref.rs @@ -110,3 +110,37 @@ mod issue_2597 { &array[idx] < val } } + +#[allow(clippy::needless_if)] +fn issue15063() { + use std::ops::BitAnd; + + macro_rules! mac { + ($e:expr) => { + $e.clone() + }; + } + + let x = 1; + if &x == &mac!(1) {} + //~^ op_ref + + #[derive(Copy, Clone)] + struct Y(i32); + impl BitAnd for Y { + type Output = Y; + fn bitand(self, rhs: Y) -> Y { + Y(self.0 & rhs.0) + } + } + impl<'a> BitAnd<&'a Y> for Y { + type Output = Y; + fn bitand(self, rhs: &'a Y) -> Y { + Y(self.0 & rhs.0) + } + } + let x = Y(1); + let y = Y(2); + let z = x & &mac!(y); + //~^ op_ref +} diff --git a/src/tools/clippy/tests/ui/op_ref.stderr b/src/tools/clippy/tests/ui/op_ref.stderr index 51c2963a9ee..8a58b154c81 100644 --- a/src/tools/clippy/tests/ui/op_ref.stderr +++ b/src/tools/clippy/tests/ui/op_ref.stderr @@ -36,5 +36,25 @@ LL | let _ = two + &three; | | | help: use the right value directly: `three` -error: aborting due to 4 previous errors +error: needlessly taken reference of both operands + --> tests/ui/op_ref.rs:125:8 + | +LL | if &x == &mac!(1) {} + | ^^^^^^^^^^^^^^ + | +help: use the values directly + | +LL - if &x == &mac!(1) {} +LL + if x == mac!(1) {} + | + +error: taken reference of right operand + --> tests/ui/op_ref.rs:144:13 + | +LL | let z = x & &mac!(y); + | ^^^^-------- + | | + | help: use the right value directly: `mac!(y)` + +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed index 34f3e046841..bcd2602edb6 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.fixed +++ b/src/tools/clippy/tests/ui/or_fun_call.fixed @@ -439,4 +439,24 @@ fn test_option_get_or_insert() { //~^ or_fun_call } +fn test_option_and() { + // assume that this is slow call + fn g() -> Option<u8> { + Some(99) + } + let mut x = Some(42_u8); + let _ = x.and_then(|_| g()); + //~^ or_fun_call +} + +fn test_result_and() { + // assume that this is slow call + fn g() -> Result<u8, ()> { + Ok(99) + } + let mut x: Result<u8, ()> = Ok(42); + let _ = x.and_then(|_| g()); + //~^ or_fun_call +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs index dc57bd6060a..8d1202ebf91 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.rs +++ b/src/tools/clippy/tests/ui/or_fun_call.rs @@ -439,4 +439,24 @@ fn test_option_get_or_insert() { //~^ or_fun_call } +fn test_option_and() { + // assume that this is slow call + fn g() -> Option<u8> { + Some(99) + } + let mut x = Some(42_u8); + let _ = x.and(g()); + //~^ or_fun_call +} + +fn test_result_and() { + // assume that this is slow call + fn g() -> Result<u8, ()> { + Ok(99) + } + let mut x: Result<u8, ()> = Ok(42); + let _ = x.and(g()); + //~^ or_fun_call +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr index 0f159fe8bff..585ee2d0e19 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.stderr +++ b/src/tools/clippy/tests/ui/or_fun_call.stderr @@ -264,5 +264,17 @@ error: function call inside of `get_or_insert` LL | let _ = x.get_or_insert(g()); | ^^^^^^^^^^^^^^^^^^ help: try: `get_or_insert_with(g)` -error: aborting due to 41 previous errors +error: function call inside of `and` + --> tests/ui/or_fun_call.rs:448:15 + | +LL | let _ = x.and(g()); + | ^^^^^^^^ help: try: `and_then(|_| g())` + +error: function call inside of `and` + --> tests/ui/or_fun_call.rs:458:15 + | +LL | let _ = x.and(g()); + | ^^^^^^^^ help: try: `and_then(|_| g())` + +error: aborting due to 43 previous errors diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed index 099c118e64e..9f6643e8d52 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed +++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed @@ -60,7 +60,7 @@ fn issue9956() { //~^ redundant_closure_call // immediately calling only one closure, so we can't remove the other ones - let a = (|| || 123); + let a = || || 123; //~^ redundant_closure_call dbg!(a()()); @@ -144,3 +144,15 @@ fn issue_12358() { // different. make_closure!(x)(); } + +#[rustfmt::skip] +fn issue_9583() { + Some(true) == Some(true); + //~^ redundant_closure_call + Some(true) == Some(true); + //~^ redundant_closure_call + Some(if 1 > 2 {1} else {2}) == Some(2); + //~^ redundant_closure_call + Some( 1 > 2 ) == Some(true); + //~^ redundant_closure_call +} diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs index da5dd7ef263..34f22878678 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs +++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs @@ -144,3 +144,15 @@ fn issue_12358() { // different. make_closure!(x)(); } + +#[rustfmt::skip] +fn issue_9583() { + (|| { Some(true) })() == Some(true); + //~^ redundant_closure_call + (|| Some(true))() == Some(true); + //~^ redundant_closure_call + (|| { Some(if 1 > 2 {1} else {2}) })() == Some(2); + //~^ redundant_closure_call + (|| { Some( 1 > 2 ) })() == Some(true); + //~^ redundant_closure_call +} diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr index 2c35aafbe31..a5591cf7813 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr +++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr @@ -95,7 +95,7 @@ error: try not to call a closure in the expression where it is declared --> tests/ui/redundant_closure_call_fixable.rs:63:13 | LL | let a = (|| || || 123)(); - | ^^^^^^^^^^^^^^^^ help: try doing something like: `(|| || 123)` + | ^^^^^^^^^^^^^^^^ help: try doing something like: `|| || 123` error: try not to call a closure in the expression where it is declared --> tests/ui/redundant_closure_call_fixable.rs:68:13 @@ -145,5 +145,29 @@ error: try not to call a closure in the expression where it is declared LL | std::convert::identity((|| 13_i32 + 36_i32)()).leading_zeros(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `13_i32 + 36_i32` -error: aborting due to 17 previous errors +error: try not to call a closure in the expression where it is declared + --> tests/ui/redundant_closure_call_fixable.rs:150:5 + | +LL | (|| { Some(true) })() == Some(true); + | ^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `Some(true)` + +error: try not to call a closure in the expression where it is declared + --> tests/ui/redundant_closure_call_fixable.rs:152:5 + | +LL | (|| Some(true))() == Some(true); + | ^^^^^^^^^^^^^^^^^ help: try doing something like: `Some(true)` + +error: try not to call a closure in the expression where it is declared + --> tests/ui/redundant_closure_call_fixable.rs:154:5 + | +LL | (|| { Some(if 1 > 2 {1} else {2}) })() == Some(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `Some(if 1 > 2 {1} else {2})` + +error: try not to call a closure in the expression where it is declared + --> tests/ui/redundant_closure_call_fixable.rs:156:5 + | +LL | (|| { Some( 1 > 2 ) })() == Some(true); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `Some( 1 > 2 )` + +error: aborting due to 21 previous errors diff --git a/src/tools/clippy/tests/ui/return_and_then.fixed b/src/tools/clippy/tests/ui/return_and_then.fixed index 8d9481d1595..8ee259b97f3 100644 --- a/src/tools/clippy/tests/ui/return_and_then.fixed +++ b/src/tools/clippy/tests/ui/return_and_then.fixed @@ -99,6 +99,92 @@ fn main() { }; None } + + #[expect(clippy::diverging_sub_expression)] + fn with_return_in_expression() -> Option<i32> { + _ = ( + return { + let x = Some("")?; + if x.len() > 2 { Some(3) } else { None } + }, + //~^ return_and_then + 10, + ); + } + + fn inside_if(a: bool, i: Option<u32>) -> Option<u32> { + if a { + let i = i?; + if i > 3 { Some(i) } else { None } + //~^ return_and_then + } else { + Some(42) + } + } + + fn inside_match(a: u32, i: Option<u32>) -> Option<u32> { + match a { + 1 | 2 => { + let i = i?; + if i > 3 { Some(i) } else { None } + }, + //~^ return_and_then + 3 | 4 => Some(42), + _ => None, + } + } + + fn inside_match_and_block_and_if(a: u32, i: Option<u32>) -> Option<u32> { + match a { + 1 | 2 => { + let a = a * 3; + if a.is_multiple_of(2) { + let i = i?; + if i > 3 { Some(i) } else { None } + //~^ return_and_then + } else { + Some(10) + } + }, + 3 | 4 => Some(42), + _ => None, + } + } + + #[expect(clippy::never_loop)] + fn with_break(i: Option<u32>) -> Option<u32> { + match i { + Some(1) => loop { + break ({ + let i = i?; + if i > 3 { Some(i) } else { None } + }); + //~^ return_and_then + }, + Some(2) => 'foo: loop { + loop { + break 'foo ({ + let i = i?; + if i > 3 { Some(i) } else { None } + }); + //~^ return_and_then + } + }, + Some(3) => 'bar: { + break 'bar ({ + let i = i?; + if i > 3 { Some(i) } else { None } + }); + //~^ return_and_then + }, + Some(4) => 'baz: loop { + _ = loop { + break i.and_then(|i| if i > 3 { Some(i) } else { None }); + }; + }, + _ => None, + } + } } fn gen_option(n: i32) -> Option<i32> { @@ -124,3 +210,48 @@ mod issue14781 { Ok(()) } } + +mod issue15111 { + #[derive(Debug)] + struct EvenOdd { + even: Option<u32>, + odd: Option<u32>, + } + + impl EvenOdd { + fn new(i: Option<u32>) -> Self { + Self { + even: i.and_then(|i| if i.is_multiple_of(2) { Some(i) } else { None }), + odd: i.and_then(|i| if i.is_multiple_of(2) { None } else { Some(i) }), + } + } + } + + fn with_if_let(i: Option<u32>) -> u32 { + if let Some(x) = i.and_then(|i| if i.is_multiple_of(2) { Some(i) } else { None }) { + x + } else { + std::hint::black_box(0) + } + } + + fn main() { + let _ = EvenOdd::new(Some(2)); + } +} + +mod issue14927 { + use std::path::Path; + struct A { + pub func: fn(check: bool, a: &Path, b: Option<&Path>), + } + const MY_A: A = A { + func: |check, a, b| { + if check { + let _ = (); + } else if let Some(parent) = b.and_then(|p| p.parent()) { + let _ = (); + } + }, + }; +} diff --git a/src/tools/clippy/tests/ui/return_and_then.rs b/src/tools/clippy/tests/ui/return_and_then.rs index beada921a91..dcb344f142b 100644 --- a/src/tools/clippy/tests/ui/return_and_then.rs +++ b/src/tools/clippy/tests/ui/return_and_then.rs @@ -90,6 +90,75 @@ fn main() { }; None } + + #[expect(clippy::diverging_sub_expression)] + fn with_return_in_expression() -> Option<i32> { + _ = ( + return Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None }), + //~^ return_and_then + 10, + ); + } + + fn inside_if(a: bool, i: Option<u32>) -> Option<u32> { + if a { + i.and_then(|i| if i > 3 { Some(i) } else { None }) + //~^ return_and_then + } else { + Some(42) + } + } + + fn inside_match(a: u32, i: Option<u32>) -> Option<u32> { + match a { + 1 | 2 => i.and_then(|i| if i > 3 { Some(i) } else { None }), + //~^ return_and_then + 3 | 4 => Some(42), + _ => None, + } + } + + fn inside_match_and_block_and_if(a: u32, i: Option<u32>) -> Option<u32> { + match a { + 1 | 2 => { + let a = a * 3; + if a.is_multiple_of(2) { + i.and_then(|i| if i > 3 { Some(i) } else { None }) + //~^ return_and_then + } else { + Some(10) + } + }, + 3 | 4 => Some(42), + _ => None, + } + } + + #[expect(clippy::never_loop)] + fn with_break(i: Option<u32>) -> Option<u32> { + match i { + Some(1) => loop { + break i.and_then(|i| if i > 3 { Some(i) } else { None }); + //~^ return_and_then + }, + Some(2) => 'foo: loop { + loop { + break 'foo i.and_then(|i| if i > 3 { Some(i) } else { None }); + //~^ return_and_then + } + }, + Some(3) => 'bar: { + break 'bar i.and_then(|i| if i > 3 { Some(i) } else { None }); + //~^ return_and_then + }, + Some(4) => 'baz: loop { + _ = loop { + break i.and_then(|i| if i > 3 { Some(i) } else { None }); + }; + }, + _ => None, + } + } } fn gen_option(n: i32) -> Option<i32> { @@ -115,3 +184,48 @@ mod issue14781 { Ok(()) } } + +mod issue15111 { + #[derive(Debug)] + struct EvenOdd { + even: Option<u32>, + odd: Option<u32>, + } + + impl EvenOdd { + fn new(i: Option<u32>) -> Self { + Self { + even: i.and_then(|i| if i.is_multiple_of(2) { Some(i) } else { None }), + odd: i.and_then(|i| if i.is_multiple_of(2) { None } else { Some(i) }), + } + } + } + + fn with_if_let(i: Option<u32>) -> u32 { + if let Some(x) = i.and_then(|i| if i.is_multiple_of(2) { Some(i) } else { None }) { + x + } else { + std::hint::black_box(0) + } + } + + fn main() { + let _ = EvenOdd::new(Some(2)); + } +} + +mod issue14927 { + use std::path::Path; + struct A { + pub func: fn(check: bool, a: &Path, b: Option<&Path>), + } + const MY_A: A = A { + func: |check, a, b| { + if check { + let _ = (); + } else if let Some(parent) = b.and_then(|p| p.parent()) { + let _ = (); + } + }, + }; +} diff --git a/src/tools/clippy/tests/ui/return_and_then.stderr b/src/tools/clippy/tests/ui/return_and_then.stderr index 5feca882860..33867ea818a 100644 --- a/src/tools/clippy/tests/ui/return_and_then.stderr +++ b/src/tools/clippy/tests/ui/return_and_then.stderr @@ -146,5 +146,99 @@ LL + if x.len() > 2 { Some(3) } else { None } LL ~ }; | -error: aborting due to 10 previous errors +error: use the `?` operator instead of an `and_then` call + --> tests/ui/return_and_then.rs:97:20 + | +LL | return Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None }), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ return { +LL + let x = Some("")?; +LL + if x.len() > 2 { Some(3) } else { None } +LL ~ }, + | + +error: use the `?` operator instead of an `and_then` call + --> tests/ui/return_and_then.rs:105:13 + | +LL | i.and_then(|i| if i > 3 { Some(i) } else { None }) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ let i = i?; +LL + if i > 3 { Some(i) } else { None } + | + +error: use the `?` operator instead of an `and_then` call + --> tests/ui/return_and_then.rs:114:22 + | +LL | 1 | 2 => i.and_then(|i| if i > 3 { Some(i) } else { None }), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ 1 | 2 => { +LL + let i = i?; +LL + if i > 3 { Some(i) } else { None } +LL ~ }, + | + +error: use the `?` operator instead of an `and_then` call + --> tests/ui/return_and_then.rs:126:21 + | +LL | i.and_then(|i| if i > 3 { Some(i) } else { None }) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ let i = i?; +LL + if i > 3 { Some(i) } else { None } + | + +error: use the `?` operator instead of an `and_then` call + --> tests/ui/return_and_then.rs:141:23 + | +LL | break i.and_then(|i| if i > 3 { Some(i) } else { None }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ break ({ +LL + let i = i?; +LL + if i > 3 { Some(i) } else { None } +LL ~ }); + | + +error: use the `?` operator instead of an `and_then` call + --> tests/ui/return_and_then.rs:146:32 + | +LL | break 'foo i.and_then(|i| if i > 3 { Some(i) } else { None }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ break 'foo ({ +LL + let i = i?; +LL + if i > 3 { Some(i) } else { None } +LL ~ }); + | + +error: use the `?` operator instead of an `and_then` call + --> tests/ui/return_and_then.rs:151:28 + | +LL | break 'bar i.and_then(|i| if i > 3 { Some(i) } else { None }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ break 'bar ({ +LL + let i = i?; +LL + if i > 3 { Some(i) } else { None } +LL ~ }); + | + +error: aborting due to 17 previous errors diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.fixed b/src/tools/clippy/tests/ui/std_instead_of_core.fixed index 1820ade422f..603ab0accb0 100644 --- a/src/tools/clippy/tests/ui/std_instead_of_core.fixed +++ b/src/tools/clippy/tests/ui/std_instead_of_core.fixed @@ -8,7 +8,6 @@ extern crate alloc; #[macro_use] extern crate proc_macro_derive; -#[warn(clippy::std_instead_of_core)] fn std_instead_of_core() { // Regular import use core::hash::Hasher; @@ -90,9 +89,3 @@ fn msrv_1_76(_: std::net::IpAddr) {} #[clippy::msrv = "1.77"] fn msrv_1_77(_: core::net::IpAddr) {} //~^ std_instead_of_core - -#[warn(clippy::std_instead_of_core)] -#[rustfmt::skip] -fn issue14982() { - use std::{collections::HashMap, hash::Hash}; -} diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.rs b/src/tools/clippy/tests/ui/std_instead_of_core.rs index 32c49330981..b6d4abad9f8 100644 --- a/src/tools/clippy/tests/ui/std_instead_of_core.rs +++ b/src/tools/clippy/tests/ui/std_instead_of_core.rs @@ -8,7 +8,6 @@ extern crate alloc; #[macro_use] extern crate proc_macro_derive; -#[warn(clippy::std_instead_of_core)] fn std_instead_of_core() { // Regular import use std::hash::Hasher; @@ -90,9 +89,3 @@ fn msrv_1_76(_: std::net::IpAddr) {} #[clippy::msrv = "1.77"] fn msrv_1_77(_: std::net::IpAddr) {} //~^ std_instead_of_core - -#[warn(clippy::std_instead_of_core)] -#[rustfmt::skip] -fn issue14982() { - use std::{collections::HashMap, hash::Hash}; -} diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.stderr b/src/tools/clippy/tests/ui/std_instead_of_core.stderr index 45d60d235ce..a5f8fbbe37c 100644 --- a/src/tools/clippy/tests/ui/std_instead_of_core.stderr +++ b/src/tools/clippy/tests/ui/std_instead_of_core.stderr @@ -1,5 +1,5 @@ error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:14:9 + --> tests/ui/std_instead_of_core.rs:13:9 | LL | use std::hash::Hasher; | ^^^ help: consider importing the item from `core`: `core` @@ -8,61 +8,61 @@ LL | use std::hash::Hasher; = help: to override `-D warnings` add `#[allow(clippy::std_instead_of_core)]` error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:17:11 + --> tests/ui/std_instead_of_core.rs:16:11 | LL | use ::std::hash::Hash; | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:23:9 + --> tests/ui/std_instead_of_core.rs:22:9 | LL | use std::fmt::{Debug, Result}; | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:28:9 + --> tests/ui/std_instead_of_core.rs:27:9 | LL | use std::{ | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:35:15 + --> tests/ui/std_instead_of_core.rs:34:15 | LL | let ptr = std::ptr::null::<u32>(); | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:37:21 + --> tests/ui/std_instead_of_core.rs:36:21 | LL | let ptr_mut = ::std::ptr::null_mut::<usize>(); | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:41:16 + --> tests/ui/std_instead_of_core.rs:40:16 | LL | let cell = std::cell::Cell::new(8u32); | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:43:27 + --> tests/ui/std_instead_of_core.rs:42:27 | LL | let cell_absolute = ::std::cell::Cell::new(8u32); | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:48:9 + --> tests/ui/std_instead_of_core.rs:47:9 | LL | use std::error::Error; | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:52:9 + --> tests/ui/std_instead_of_core.rs:51:9 | LL | use std::iter::Iterator; | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `alloc` - --> tests/ui/std_instead_of_core.rs:59:9 + --> tests/ui/std_instead_of_core.rs:58:9 | LL | use std::vec; | ^^^ help: consider importing the item from `alloc`: `alloc` @@ -71,13 +71,13 @@ LL | use std::vec; = help: to override `-D warnings` add `#[allow(clippy::std_instead_of_alloc)]` error: used import from `std` instead of `alloc` - --> tests/ui/std_instead_of_core.rs:61:9 + --> tests/ui/std_instead_of_core.rs:60:9 | LL | use std::vec::Vec; | ^^^ help: consider importing the item from `alloc`: `alloc` error: used import from `alloc` instead of `core` - --> tests/ui/std_instead_of_core.rs:67:9 + --> tests/ui/std_instead_of_core.rs:66:9 | LL | use alloc::slice::from_ref; | ^^^^^ help: consider importing the item from `core`: `core` @@ -86,13 +86,13 @@ LL | use alloc::slice::from_ref; = help: to override `-D warnings` add `#[allow(clippy::alloc_instead_of_core)]` error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:82:9 + --> tests/ui/std_instead_of_core.rs:81:9 | LL | std::intrinsics::copy(a, b, 1); | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:91:17 + --> tests/ui/std_instead_of_core.rs:90:17 | LL | fn msrv_1_77(_: std::net::IpAddr) {} | ^^^ help: consider importing the item from `core`: `core` diff --git a/src/tools/clippy/tests/ui/std_instead_of_core_unfixable.rs b/src/tools/clippy/tests/ui/std_instead_of_core_unfixable.rs new file mode 100644 index 00000000000..957f472a454 --- /dev/null +++ b/src/tools/clippy/tests/ui/std_instead_of_core_unfixable.rs @@ -0,0 +1,18 @@ +//@no-rustfix + +#![warn(clippy::std_instead_of_core)] +#![warn(clippy::std_instead_of_alloc)] +#![allow(unused_imports)] + +#[rustfmt::skip] +fn issue14982() { + use std::{collections::HashMap, hash::Hash}; + //~^ std_instead_of_core +} + +#[rustfmt::skip] +fn issue15143() { + use std::{error::Error, vec::Vec, fs::File}; + //~^ std_instead_of_core + //~| std_instead_of_alloc +} diff --git a/src/tools/clippy/tests/ui/std_instead_of_core_unfixable.stderr b/src/tools/clippy/tests/ui/std_instead_of_core_unfixable.stderr new file mode 100644 index 00000000000..0cdec56c992 --- /dev/null +++ b/src/tools/clippy/tests/ui/std_instead_of_core_unfixable.stderr @@ -0,0 +1,30 @@ +error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core_unfixable.rs:9:43 + | +LL | use std::{collections::HashMap, hash::Hash}; + | ^^^^ + | + = help: consider importing the item from `core` + = note: `-D clippy::std-instead-of-core` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::std_instead_of_core)]` + +error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core_unfixable.rs:15:22 + | +LL | use std::{error::Error, vec::Vec, fs::File}; + | ^^^^^ + | + = help: consider importing the item from `core` + +error: used import from `std` instead of `alloc` + --> tests/ui/std_instead_of_core_unfixable.rs:15:34 + | +LL | use std::{error::Error, vec::Vec, fs::File}; + | ^^^ + | + = help: consider importing the item from `alloc` + = note: `-D clippy::std-instead-of-alloc` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::std_instead_of_alloc)]` + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/swap_with_temporary.fixed b/src/tools/clippy/tests/ui/swap_with_temporary.fixed index 4007d998ba0..4b4b0d4aebd 100644 --- a/src/tools/clippy/tests/ui/swap_with_temporary.fixed +++ b/src/tools/clippy/tests/ui/swap_with_temporary.fixed @@ -72,3 +72,49 @@ fn dont_lint_those(s: &mut S, v: &mut [String], w: Option<&mut String>) { swap(&mut s.t, v.get_mut(0).unwrap()); swap(w.unwrap(), &mut s.t); } + +fn issue15166() { + use std::sync::Mutex; + + struct A { + thing: Mutex<Vec<u8>>, + } + + impl A { + fn a(&self) { + let mut new_vec = vec![42]; + // Do not lint here, as neither `new_vec` nor the result of `.lock().unwrap()` are temporaries + swap(&mut new_vec, &mut self.thing.lock().unwrap()); + for v in new_vec { + // Do something with v + } + // Here `vec![42]` is temporary though, and a proper dereference will have to be used in the fix + *self.thing.lock().unwrap() = vec![42]; + //~^ ERROR: swapping with a temporary value is inefficient + } + } +} + +fn multiple_deref() { + let mut v1 = &mut &mut &mut vec![42]; + ***v1 = vec![]; + //~^ ERROR: swapping with a temporary value is inefficient + + struct Wrapper<T: ?Sized>(T); + impl<T: ?Sized> std::ops::Deref for Wrapper<T> { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl<T: ?Sized> std::ops::DerefMut for Wrapper<T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + use std::sync::Mutex; + let mut v1 = Mutex::new(Wrapper(Wrapper(vec![42]))); + ***v1.lock().unwrap() = vec![]; + //~^ ERROR: swapping with a temporary value is inefficient +} diff --git a/src/tools/clippy/tests/ui/swap_with_temporary.rs b/src/tools/clippy/tests/ui/swap_with_temporary.rs index d403c086c0f..8e35e6144d9 100644 --- a/src/tools/clippy/tests/ui/swap_with_temporary.rs +++ b/src/tools/clippy/tests/ui/swap_with_temporary.rs @@ -72,3 +72,49 @@ fn dont_lint_those(s: &mut S, v: &mut [String], w: Option<&mut String>) { swap(&mut s.t, v.get_mut(0).unwrap()); swap(w.unwrap(), &mut s.t); } + +fn issue15166() { + use std::sync::Mutex; + + struct A { + thing: Mutex<Vec<u8>>, + } + + impl A { + fn a(&self) { + let mut new_vec = vec![42]; + // Do not lint here, as neither `new_vec` nor the result of `.lock().unwrap()` are temporaries + swap(&mut new_vec, &mut self.thing.lock().unwrap()); + for v in new_vec { + // Do something with v + } + // Here `vec![42]` is temporary though, and a proper dereference will have to be used in the fix + swap(&mut vec![42], &mut self.thing.lock().unwrap()); + //~^ ERROR: swapping with a temporary value is inefficient + } + } +} + +fn multiple_deref() { + let mut v1 = &mut &mut &mut vec![42]; + swap(&mut ***v1, &mut vec![]); + //~^ ERROR: swapping with a temporary value is inefficient + + struct Wrapper<T: ?Sized>(T); + impl<T: ?Sized> std::ops::Deref for Wrapper<T> { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl<T: ?Sized> std::ops::DerefMut for Wrapper<T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + use std::sync::Mutex; + let mut v1 = Mutex::new(Wrapper(Wrapper(vec![42]))); + swap(&mut vec![], &mut v1.lock().unwrap()); + //~^ ERROR: swapping with a temporary value is inefficient +} diff --git a/src/tools/clippy/tests/ui/swap_with_temporary.stderr b/src/tools/clippy/tests/ui/swap_with_temporary.stderr index 59355771a96..5ca4fccd37a 100644 --- a/src/tools/clippy/tests/ui/swap_with_temporary.stderr +++ b/src/tools/clippy/tests/ui/swap_with_temporary.stderr @@ -96,5 +96,41 @@ note: this expression returns a temporary value LL | swap(mac!(refmut y), &mut func()); | ^^^^^^ -error: aborting due to 8 previous errors +error: swapping with a temporary value is inefficient + --> tests/ui/swap_with_temporary.rs:92:13 + | +LL | swap(&mut vec![42], &mut self.thing.lock().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use assignment instead: `*self.thing.lock().unwrap() = vec![42]` + | +note: this expression returns a temporary value + --> tests/ui/swap_with_temporary.rs:92:23 + | +LL | swap(&mut vec![42], &mut self.thing.lock().unwrap()); + | ^^^^^^^^ + +error: swapping with a temporary value is inefficient + --> tests/ui/swap_with_temporary.rs:100:5 + | +LL | swap(&mut ***v1, &mut vec![]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use assignment instead: `***v1 = vec![]` + | +note: this expression returns a temporary value + --> tests/ui/swap_with_temporary.rs:100:27 + | +LL | swap(&mut ***v1, &mut vec![]); + | ^^^^^^ + +error: swapping with a temporary value is inefficient + --> tests/ui/swap_with_temporary.rs:118:5 + | +LL | swap(&mut vec![], &mut v1.lock().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use assignment instead: `***v1.lock().unwrap() = vec![]` + | +note: this expression returns a temporary value + --> tests/ui/swap_with_temporary.rs:118:15 + | +LL | swap(&mut vec![], &mut v1.lock().unwrap()); + | ^^^^^^ + +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/track-diagnostics-clippy.rs b/src/tools/clippy/tests/ui/track-diagnostics-clippy.rs index 2e67fb65efc..3bae23f1984 100644 --- a/src/tools/clippy/tests/ui/track-diagnostics-clippy.rs +++ b/src/tools/clippy/tests/ui/track-diagnostics-clippy.rs @@ -4,6 +4,7 @@ // Normalize the emitted location so this doesn't need // updating everytime someone adds or removes a line. //@normalize-stderr-test: ".rs:\d+:\d+" -> ".rs:LL:CC" +//@normalize-stderr-test: "src/tools/clippy/" -> "" #![warn(clippy::let_and_return, clippy::unnecessary_cast)] @@ -12,7 +13,7 @@ fn main() { let a = 3u32; let b = a as u32; //~^ unnecessary_cast - + // Check the provenance of a lint sent through `TyCtxt::node_span_lint()` let c = { let d = 42; diff --git a/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr b/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr index 9d6538112bf..d5533877b45 100644 --- a/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr +++ b/src/tools/clippy/tests/ui/track-diagnostics-clippy.stderr @@ -4,7 +4,7 @@ error: casting to the same type is unnecessary (`u32` -> `u32`) LL | let b = a as u32; | ^^^^^^^^ help: try: `a` | - = note: -Ztrack-diagnostics: created at src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs:LL:CC + = note: -Ztrack-diagnostics: created at clippy_lints/src/casts/unnecessary_cast.rs:LL:CC = note: `-D clippy::unnecessary-cast` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]` @@ -16,7 +16,7 @@ LL | let d = 42; LL | d | ^ | - = note: -Ztrack-diagnostics: created at src/tools/clippy/clippy_lints/src/returns.rs:LL:CC + = note: -Ztrack-diagnostics: created at clippy_lints/src/returns.rs:LL:CC = note: `-D clippy::let-and-return` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::let_and_return)]` help: return the expression directly diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.fixed b/src/tools/clippy/tests/ui/unnecessary_map_or.fixed index 3c724397284..3109c4af8e2 100644 --- a/src/tools/clippy/tests/ui/unnecessary_map_or.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_map_or.fixed @@ -130,3 +130,13 @@ fn issue14201(a: Option<String>, b: Option<String>, s: &String) -> bool { //~^ unnecessary_map_or x && y } + +fn issue15180() { + let s = std::sync::Mutex::new(Some("foo")); + _ = s.lock().unwrap().is_some_and(|s| s == "foo"); + //~^ unnecessary_map_or + + let s = &&&&Some("foo"); + _ = s.is_some_and(|s| s == "foo"); + //~^ unnecessary_map_or +} diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.rs b/src/tools/clippy/tests/ui/unnecessary_map_or.rs index e734a27bada..52a55f9fc9e 100644 --- a/src/tools/clippy/tests/ui/unnecessary_map_or.rs +++ b/src/tools/clippy/tests/ui/unnecessary_map_or.rs @@ -134,3 +134,13 @@ fn issue14201(a: Option<String>, b: Option<String>, s: &String) -> bool { //~^ unnecessary_map_or x && y } + +fn issue15180() { + let s = std::sync::Mutex::new(Some("foo")); + _ = s.lock().unwrap().map_or(false, |s| s == "foo"); + //~^ unnecessary_map_or + + let s = &&&&Some("foo"); + _ = s.map_or(false, |s| s == "foo"); + //~^ unnecessary_map_or +} diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.stderr b/src/tools/clippy/tests/ui/unnecessary_map_or.stderr index 0f9466a6a6b..99e17e8b34b 100644 --- a/src/tools/clippy/tests/ui/unnecessary_map_or.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_map_or.stderr @@ -326,5 +326,29 @@ LL - let y = b.map_or(true, |b| b == *s); LL + let y = b.is_none_or(|b| b == *s); | -error: aborting due to 26 previous errors +error: this `map_or` can be simplified + --> tests/ui/unnecessary_map_or.rs:140:9 + | +LL | _ = s.lock().unwrap().map_or(false, |s| s == "foo"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use is_some_and instead + | +LL - _ = s.lock().unwrap().map_or(false, |s| s == "foo"); +LL + _ = s.lock().unwrap().is_some_and(|s| s == "foo"); + | + +error: this `map_or` can be simplified + --> tests/ui/unnecessary_map_or.rs:144:9 + | +LL | _ = s.map_or(false, |s| s == "foo"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use is_some_and instead + | +LL - _ = s.map_or(false, |s| s == "foo"); +LL + _ = s.is_some_and(|s| s == "foo"); + | + +error: aborting due to 28 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.fixed b/src/tools/clippy/tests/ui/unnecessary_operation.fixed index 645b56fe95e..ac9fa4de20a 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_operation.fixed @@ -144,3 +144,16 @@ const fn foo() { assert!([42, 55].len() > get_usize()); //~^ unnecessary_operation } + +fn issue15173() { + // No lint as `Box::new(None)` alone would be ambiguous + Box::new(None) as Box<Option<i32>>; +} + +#[expect(clippy::redundant_closure_call)] +fn issue15173_original<MsU>(handler: impl FnOnce() -> MsU + Clone + 'static) { + Box::new(move |value| { + (|_| handler.clone()())(value); + None + }) as Box<dyn Fn(i32) -> Option<i32>>; +} diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.rs b/src/tools/clippy/tests/ui/unnecessary_operation.rs index 97e90269c5c..a3e6c6288ad 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.rs +++ b/src/tools/clippy/tests/ui/unnecessary_operation.rs @@ -150,3 +150,16 @@ const fn foo() { [42, 55][get_usize()]; //~^ unnecessary_operation } + +fn issue15173() { + // No lint as `Box::new(None)` alone would be ambiguous + Box::new(None) as Box<Option<i32>>; +} + +#[expect(clippy::redundant_closure_call)] +fn issue15173_original<MsU>(handler: impl FnOnce() -> MsU + Clone + 'static) { + Box::new(move |value| { + (|_| handler.clone()())(value); + None + }) as Box<dyn Fn(i32) -> Option<i32>>; +} diff --git a/src/tools/clippy/tests/ui/zero_ptr.fixed b/src/tools/clippy/tests/ui/zero_ptr.fixed index f2375d57f3a..f9d9d2db176 100644 --- a/src/tools/clippy/tests/ui/zero_ptr.fixed +++ b/src/tools/clippy/tests/ui/zero_ptr.fixed @@ -16,3 +16,11 @@ fn main() { let z = 0; let _ = z as *const usize; // this is currently not caught } + +const fn in_const_context() { + #[clippy::msrv = "1.23"] + let _: *const usize = 0 as *const _; + #[clippy::msrv = "1.24"] + let _: *const usize = std::ptr::null(); + //~^ zero_ptr +} diff --git a/src/tools/clippy/tests/ui/zero_ptr.rs b/src/tools/clippy/tests/ui/zero_ptr.rs index ee01e426a43..41455fee5b5 100644 --- a/src/tools/clippy/tests/ui/zero_ptr.rs +++ b/src/tools/clippy/tests/ui/zero_ptr.rs @@ -16,3 +16,11 @@ fn main() { let z = 0; let _ = z as *const usize; // this is currently not caught } + +const fn in_const_context() { + #[clippy::msrv = "1.23"] + let _: *const usize = 0 as *const _; + #[clippy::msrv = "1.24"] + let _: *const usize = 0 as *const _; + //~^ zero_ptr +} diff --git a/src/tools/clippy/tests/ui/zero_ptr.stderr b/src/tools/clippy/tests/ui/zero_ptr.stderr index 8dc781f3625..81269de6c60 100644 --- a/src/tools/clippy/tests/ui/zero_ptr.stderr +++ b/src/tools/clippy/tests/ui/zero_ptr.stderr @@ -31,5 +31,11 @@ error: `0 as *mut _` detected LL | foo(0 as *const _, 0 as *mut _); | ^^^^^^^^^^^ help: try: `std::ptr::null_mut()` -error: aborting due to 5 previous errors +error: `0 as *const _` detected + --> tests/ui/zero_ptr.rs:24:27 + | +LL | let _: *const usize = 0 as *const _; + | ^^^^^^^^^^^^^ help: try: `std::ptr::null()` + +error: aborting due to 6 previous errors |
