diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 7fd9c28c43f2b..afb07f57ab7a7 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -19,6 +19,7 @@ #![warn(unused_lifetimes)] #![deny(clippy::pattern_type_mismatch)] #![expect(clippy::uninlined_format_args)] +#![allow(clippy::collapsible_match)] // The rustc crates we need extern crate rustc_abi; diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 795eba1dfeaf0..7c798a3c2e5a6 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -8,6 +8,11 @@ document. [92b4b68...master](https://github.com/rust-lang/rust-clippy/compare/92b4b68...master) +### New Lints + +* Added [`unnecessary_trailing_comma`] to `style` (single-line format-like macros only) + [#13965](https://github.com/rust-lang/rust-clippy/issues/13965) + ## Rust 1.93 Current stable, released 2026-01-22 @@ -6433,6 +6438,7 @@ Released 2018-09-13 [`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord [`derive_partial_eq_without_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq [`derived_hash_with_manual_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derived_hash_with_manual_eq +[`disallowed_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_fields [`disallowed_macros`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros [`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method [`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods @@ -7136,6 +7142,7 @@ Released 2018-09-13 [`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by [`unnecessary_struct_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_struct_initialization [`unnecessary_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned +[`unnecessary_trailing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_trailing_comma [`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap [`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps [`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern @@ -7233,6 +7240,7 @@ Released 2018-09-13 [`allow-renamed-params-for`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-renamed-params-for [`allow-unwrap-in-consts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-unwrap-in-consts [`allow-unwrap-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-unwrap-in-tests +[`allow-unwrap-types`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-unwrap-types [`allow-useless-vec-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-useless-vec-in-tests [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles [`allowed-duplicate-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-duplicate-crates @@ -7252,6 +7260,7 @@ Released 2018-09-13 [`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items [`cognitive-complexity-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cognitive-complexity-threshold [`const-literal-digits-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#const-literal-digits-threshold +[`disallowed-fields`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-fields [`disallowed-macros`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-macros [`disallowed-methods`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-methods [`disallowed-names`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-names diff --git a/src/tools/clippy/book/src/configuration.md b/src/tools/clippy/book/src/configuration.md index b130544318980..b270c11ab397c 100644 --- a/src/tools/clippy/book/src/configuration.md +++ b/src/tools/clippy/book/src/configuration.md @@ -2,13 +2,17 @@ > **Note:** The configuration file is unstable and may be deprecated in the future. -Some lints can be configured in a TOML file named `clippy.toml` or `.clippy.toml`, which is searched for in: +Some lints can be configured in a TOML file named `clippy.toml` or `.clippy.toml`, which is searched for starting in the +first defined directory according to the following priority order: 1. The directory specified by the `CLIPPY_CONF_DIR` environment variable, or 2. The directory specified by the [CARGO_MANIFEST_DIR](https://doc.rust-lang.org/cargo/reference/environment-variables.html) environment variable, or 3. The current directory. +If the chosen directory does not contain a configuration file, Clippy will walk up the directory tree, searching each +parent directory until it finds one or reaches the filesystem root. + It contains a basic `variable = value` mapping e.g. ```toml diff --git a/src/tools/clippy/book/src/development/infrastructure/changelog_update.md b/src/tools/clippy/book/src/development/infrastructure/changelog_update.md index 9eb7e7cc9c9eb..4652d71a9ea33 100644 --- a/src/tools/clippy/book/src/development/infrastructure/changelog_update.md +++ b/src/tools/clippy/book/src/development/infrastructure/changelog_update.md @@ -28,8 +28,8 @@ bullet points might be helpful: check out the Clippy commit of the current Rust `beta` branch. [Link][rust_beta_tools] * When writing the release notes for the **upcoming beta release**, you need to - check out the Clippy commit of the current Rust `master`. - [Link][rust_master_tools] + check out the Clippy commit of the current Rust `main`. + [Link][rust_main_tools] * When writing the (forgotten) release notes for a **past stable release**, you need to check out the Rust release tag of the stable release. [Link][rust_stable_tools] @@ -112,7 +112,7 @@ written for. If not, update the version to the changelog version. [changelog]: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md [forge]: https://forge.rust-lang.org/ -[rust_master_tools]: https://github.com/rust-lang/rust/tree/HEAD/src/tools/clippy +[rust_main_tools]: https://github.com/rust-lang/rust/tree/HEAD/src/tools/clippy [rust_beta_tools]: https://github.com/rust-lang/rust/tree/beta/src/tools/clippy [rust_stable_tools]: https://github.com/rust-lang/rust/releases [`beta-accepted`]: https://github.com/rust-lang/rust-clippy/issues?q=label%3Abeta-accepted+ diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index 57ac01828e597..c87f8e9a68de1 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -214,6 +214,23 @@ Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` * [`unwrap_used`](https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used) +## `allow-unwrap-types` +List of types to allow `unwrap()` and `expect()` on. + +#### Example + +```toml +allow-unwrap-types = [ "std::sync::LockResult" ] +``` + +**Default Value:** `[]` + +--- +**Affected lints:** +* [`expect_used`](https://rust-lang.github.io/rust-clippy/master/index.html#expect_used) +* [`unwrap_used`](https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used) + + ## `allow-useless-vec-in-tests` Whether `useless_vec` should ignore test functions or `#[cfg(test)]` @@ -505,6 +522,23 @@ The minimum digits a const float literal must have to supress the `excessive_pre * [`excessive_precision`](https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision) +## `disallowed-fields` +The list of disallowed fields, written as fully qualified paths. + +**Fields:** +- `path` (required): the fully qualified path to the field that should be disallowed +- `reason` (optional): explanation why this field is disallowed +- `replacement` (optional): suggested alternative method +- `allow-invalid` (optional, `false` by default): when set to `true`, it will ignore this entry + if the path doesn't exist, instead of emitting an error + +**Default Value:** `[]` + +--- +**Affected lints:** +* [`disallowed_fields`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_fields) + + ## `disallowed-macros` The list of disallowed macros, written as fully qualified paths. diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs index 3f4997a395a8e..41099f94b0448 100644 --- a/src/tools/clippy/clippy_config/src/conf.rs +++ b/src/tools/clippy/clippy_config/src/conf.rs @@ -413,6 +413,15 @@ define_Conf! { /// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` #[lints(unwrap_used)] allow_unwrap_in_tests: bool = false, + /// List of types to allow `unwrap()` and `expect()` on. + /// + /// #### Example + /// + /// ```toml + /// allow-unwrap-types = [ "std::sync::LockResult" ] + /// ``` + #[lints(expect_used, unwrap_used)] + allow_unwrap_types: Vec = Vec::new(), /// Whether `useless_vec` should ignore test functions or `#[cfg(test)]` #[lints(useless_vec)] allow_useless_vec_in_tests: bool = false, @@ -581,6 +590,17 @@ define_Conf! { /// Use the Cognitive Complexity lint instead. #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)] cyclomatic_complexity_threshold: u64 = 25, + /// The list of disallowed fields, written as fully qualified paths. + /// + /// **Fields:** + /// - `path` (required): the fully qualified path to the field that should be disallowed + /// - `reason` (optional): explanation why this field is disallowed + /// - `replacement` (optional): suggested alternative method + /// - `allow-invalid` (optional, `false` by default): when set to `true`, it will ignore this entry + /// if the path doesn't exist, instead of emitting an error + #[disallowed_paths_allow_replacements = true] + #[lints(disallowed_fields)] + disallowed_fields: Vec = Vec::new(), /// The list of disallowed macros, written as fully qualified paths. /// /// **Fields:** diff --git a/src/tools/clippy/clippy_dev/src/edit_lints.rs b/src/tools/clippy/clippy_dev/src/edit_lints.rs index fb1c1458c50cd..411bf530b22bf 100644 --- a/src/tools/clippy/clippy_dev/src/edit_lints.rs +++ b/src/tools/clippy/clippy_dev/src/edit_lints.rs @@ -1,11 +1,13 @@ use crate::parse::cursor::{self, Capture, Cursor}; -use crate::parse::{DeprecatedLint, Lint, ParseCx, RenamedLint}; +use crate::parse::{ActiveLint, DeprecatedLint, Lint, LintData, LintName, ParseCx, RenamedLint}; use crate::update_lints::generate_lint_files; use crate::utils::{ ErrAction, FileUpdater, UpdateMode, UpdateStatus, Version, delete_dir_if_exists, delete_file_if_exists, expect_action, try_rename_dir, try_rename_file, walk_dir_no_dot_or_target, }; +use core::mem; use rustc_lexer::TokenKind; +use std::collections::hash_map::Entry; use std::ffi::OsString; use std::fs; use std::path::Path; @@ -20,74 +22,51 @@ use std::path::Path; /// /// If a file path could not read from or written to pub fn deprecate<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, name: &'env str, reason: &'env str) { - let mut lints = cx.find_lint_decls(); - let (mut deprecated_lints, renamed_lints) = cx.read_deprecated_lints(); + let mut data = cx.parse_lint_decls(); - let Some(lint_idx) = lints.iter().position(|l| l.name == name) else { + let Entry::Occupied(mut lint) = data.lints.entry(name) else { eprintln!("error: failed to find lint `{name}`"); return; }; + let Lint::Active(prev_lint) = mem::replace( + lint.get_mut(), + Lint::Deprecated(DeprecatedLint { + reason, + version: cx.str_buf.alloc_display(cx.arena, clippy_version.rust_display()), + }), + ) else { + eprintln!("error: `{name}` is already deprecated"); + return; + }; - let prefixed_name = cx.str_buf.with(|buf| { - buf.extend(["clippy::", name]); - cx.arena.alloc_str(buf) - }); - match deprecated_lints.binary_search_by(|x| x.name.cmp(prefixed_name)) { - Ok(_) => { - println!("`{name}` is already deprecated"); - return; - }, - Err(idx) => deprecated_lints.insert( - idx, - DeprecatedLint { - name: prefixed_name, - reason, - version: cx.str_buf.alloc_display(cx.arena, clippy_version.rust_display()), - }, - ), - } - - remove_lint_declaration(lint_idx, &mut lints, &mut FileUpdater::default()); - generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); + remove_lint_declaration(name, &prev_lint, &data, &mut FileUpdater::default()); + generate_lint_files(UpdateMode::Change, &data); println!("info: `{name}` has successfully been deprecated"); println!("note: you must run `cargo uitest` to update the test results"); } pub fn uplift<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_name: &'env str, new_name: &'env str) { - let mut lints = cx.find_lint_decls(); - let (deprecated_lints, mut renamed_lints) = cx.read_deprecated_lints(); + let mut data = cx.parse_lint_decls(); + + update_rename_targets(&mut data, old_name, LintName::new_rustc(new_name)); - let Some(lint_idx) = lints.iter().position(|l| l.name == old_name) else { + let Entry::Occupied(mut lint) = data.lints.entry(old_name) else { eprintln!("error: failed to find lint `{old_name}`"); return; }; - - let old_name_prefixed = cx.str_buf.with(|buf| { - buf.extend(["clippy::", old_name]); - cx.arena.alloc_str(buf) - }); - for lint in &mut renamed_lints { - if lint.new_name == old_name_prefixed { - lint.new_name = new_name; - } - } - match renamed_lints.binary_search_by(|x| x.old_name.cmp(old_name_prefixed)) { - Ok(_) => { - println!("`{old_name}` is already deprecated"); - return; - }, - Err(idx) => renamed_lints.insert( - idx, - RenamedLint { - old_name: old_name_prefixed, - new_name, - version: cx.str_buf.alloc_display(cx.arena, clippy_version.rust_display()), - }, - ), - } + let Lint::Active(prev_lint) = mem::replace( + lint.get_mut(), + Lint::Renamed(RenamedLint { + new_name: LintName::new_rustc(new_name), + version: cx.str_buf.alloc_display(cx.arena, clippy_version.rust_display()), + }), + ) else { + eprintln!("error: `{old_name}` is already deprecated"); + return; + }; let mut updater = FileUpdater::default(); - let remove_mod = remove_lint_declaration(lint_idx, &mut lints, &mut updater); + let remove_mod = remove_lint_declaration(old_name, &prev_lint, &data, &mut updater); let mut update_fn = uplift_update_fn(old_name, new_name, remove_mod); for e in walk_dir_no_dot_or_target(".") { let e = expect_action(e, ErrAction::Read, "."); @@ -95,7 +74,7 @@ pub fn uplift<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_nam updater.update_file(e.path(), &mut update_fn); } } - generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); + generate_lint_files(UpdateMode::Change, &data); println!("info: `{old_name}` has successfully been uplifted as `{new_name}`"); println!("note: you must run `cargo uitest` to update the test results"); } @@ -117,79 +96,50 @@ pub fn uplift<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_nam /// * If `old_name` names a deprecated or renamed lint. pub fn rename<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_name: &'env str, new_name: &'env str) { let mut updater = FileUpdater::default(); - let mut lints = cx.find_lint_decls(); - let (deprecated_lints, mut renamed_lints) = cx.read_deprecated_lints(); + let mut data = cx.parse_lint_decls(); - let Ok(lint_idx) = lints.binary_search_by(|x| x.name.cmp(old_name)) else { - panic!("could not find lint `{old_name}`"); - }; + update_rename_targets(&mut data, old_name, LintName::new_clippy(new_name)); - let old_name_prefixed = cx.str_buf.with(|buf| { - buf.extend(["clippy::", old_name]); - cx.arena.alloc_str(buf) - }); - let new_name_prefixed = cx.str_buf.with(|buf| { - buf.extend(["clippy::", new_name]); - cx.arena.alloc_str(buf) - }); - - for lint in &mut renamed_lints { - if lint.new_name == old_name_prefixed { - lint.new_name = new_name_prefixed; - } - } - match renamed_lints.binary_search_by(|x| x.old_name.cmp(old_name_prefixed)) { - Ok(_) => { - println!("`{old_name}` already has a rename registered"); - return; - }, - Err(idx) => { - renamed_lints.insert( - idx, - RenamedLint { - old_name: old_name_prefixed, - new_name: new_name_prefixed, - version: cx.str_buf.alloc_display(cx.arena, clippy_version.rust_display()), - }, - ); - }, - } + let Entry::Occupied(mut lint) = data.lints.entry(old_name) else { + eprintln!("error: failed to find lint `{old_name}`"); + return; + }; + let Lint::Active(mut prev_lint) = mem::replace( + lint.get_mut(), + Lint::Renamed(RenamedLint { + new_name: LintName::new_clippy(new_name), + version: cx.str_buf.alloc_display(cx.arena, clippy_version.rust_display()), + }), + ) else { + eprintln!("error: `{old_name}` is already deprecated"); + return; + }; let mut rename_mod = false; - if lints.binary_search_by(|x| x.name.cmp(new_name)).is_err() { - let lint = &mut lints[lint_idx]; - if lint.module.ends_with(old_name) - && lint + if let Entry::Vacant(e) = data.lints.entry(new_name) { + if prev_lint.module.ends_with(old_name) + && prev_lint .path .file_stem() .is_some_and(|x| x.as_encoded_bytes() == old_name.as_bytes()) { - let mut new_path = lint.path.with_file_name(new_name).into_os_string(); + let mut new_path = prev_lint.path.with_file_name(new_name).into_os_string(); new_path.push(".rs"); - if try_rename_file(lint.path.as_ref(), new_path.as_ref()) { + if try_rename_file(prev_lint.path.as_ref(), new_path.as_ref()) { rename_mod = true; } - lint.module = cx.str_buf.with(|buf| { - buf.push_str(&lint.module[..lint.module.len() - old_name.len()]); + prev_lint.module = cx.str_buf.with(|buf| { + buf.push_str(&prev_lint.module[..prev_lint.module.len() - old_name.len()]); buf.push_str(new_name); cx.arena.alloc_str(buf) }); } + e.insert(Lint::Active(prev_lint)); - rename_test_files( - old_name, - new_name, - &lints[lint_idx + 1..] - .iter() - .map(|l| l.name) - .take_while(|&n| n.starts_with(old_name)) - .collect::>(), - ); - lints[lint_idx].name = new_name; - lints.sort_by(|lhs, rhs| lhs.name.cmp(rhs.name)); + rename_test_files(old_name, new_name, &create_ignored_prefixes(old_name, &data)); } else { - println!("Renamed `clippy::{old_name}` to `clippy::{new_name}`"); + println!("Renamed `{old_name}` to `{new_name}`"); println!("Since `{new_name}` already exists the existing code has not been changed"); return; } @@ -201,9 +151,9 @@ pub fn rename<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_nam updater.update_file(e.path(), &mut update_fn); } } - generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints); + generate_lint_files(UpdateMode::Change, &data); - println!("Renamed `clippy::{old_name}` to `clippy::{new_name}`"); + println!("Renamed `{old_name}` to `{new_name}`"); println!("All code referencing the old name has been updated"); println!("Make sure to inspect the results as some things may have been missed"); println!("note: `cargo uibless` still needs to be run to update the test results"); @@ -211,9 +161,14 @@ pub fn rename<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, old_nam /// Removes a lint's declaration and test files. Returns whether the module containing the /// lint was deleted. -fn remove_lint_declaration(lint_idx: usize, lints: &mut Vec>, updater: &mut FileUpdater) -> bool { - let lint = lints.remove(lint_idx); - let delete_mod = if lints.iter().all(|l| l.module != lint.module) { +fn remove_lint_declaration(name: &str, lint: &ActiveLint<'_>, data: &LintData<'_>, updater: &mut FileUpdater) -> bool { + let delete_mod = if data.lints.iter().all(|(_, l)| { + if let Lint::Active(l) = l { + l.module != lint.module + } else { + true + } + }) { delete_file_if_exists(lint.path.as_ref()) } else { updater.update_file(&lint.path, &mut |_, src, dst| -> UpdateStatus { @@ -231,18 +186,35 @@ fn remove_lint_declaration(lint_idx: usize, lints: &mut Vec>, updater: }); false }; - delete_test_files( - lint.name, - &lints[lint_idx..] - .iter() - .map(|l| l.name) - .take_while(|&n| n.starts_with(lint.name)) - .collect::>(), - ); + delete_test_files(name, &create_ignored_prefixes(name, data)); delete_mod } +/// Updates all renames to the old name to be renames to the new name. +/// +/// This is needed because rustc doesn't allow a lint to be renamed to a lint that has +/// also been renamed. +fn update_rename_targets<'cx>(data: &mut LintData<'cx>, old_name: &str, new_name: LintName<'cx>) { + let old_name = LintName::new_clippy(old_name); + for lint in data.lints.values_mut() { + if let Lint::Renamed(lint) = lint + && lint.new_name == old_name + { + lint.new_name = new_name; + } + } +} + +/// Creates a list of prefixes to ignore when +fn create_ignored_prefixes<'cx>(name: &str, data: &LintData<'cx>) -> Vec<&'cx str> { + data.lints + .keys() + .copied() + .filter(|&x| x.len() > name.len() && x.starts_with(name)) + .collect() +} + fn collect_ui_test_names(lint: &str, ignored_prefixes: &[&str], dst: &mut Vec<(OsString, bool)>) { for e in fs::read_dir("tests/ui").expect("error reading `tests/ui`") { let e = e.expect("error reading `tests/ui`"); diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs index 69309403c8d02..cff51d34c30e6 100644 --- a/src/tools/clippy/clippy_dev/src/lib.rs +++ b/src/tools/clippy/clippy_dev/src/lib.rs @@ -19,6 +19,7 @@ #![allow(clippy::missing_panics_doc)] extern crate rustc_arena; +extern crate rustc_data_structures; #[expect(unused_extern_crates, reason = "required to link to rustc crates")] extern crate rustc_driver; extern crate rustc_lexer; diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs index 72f281ca4d9d7..2abe471bed2bd 100644 --- a/src/tools/clippy/clippy_dev/src/new_lint.rs +++ b/src/tools/clippy/clippy_dev/src/new_lint.rs @@ -526,18 +526,14 @@ fn parse_mod_file(path: &Path, contents: &str) -> (&'static str, usize) { let mut captures = [Capture::EMPTY]; while let Some(name) = cursor.find_any_ident() { match cursor.get_text(name) { - "declare_clippy_lint" => { - if cursor.match_all(&[Bang, OpenBrace], &mut []) && cursor.find_pat(CloseBrace) { - decl_end = Some(cursor.pos()); - } + "declare_clippy_lint" if cursor.match_all(&[Bang, OpenBrace], &mut []) && cursor.find_pat(CloseBrace) => { + decl_end = Some(cursor.pos()); }, - "impl" => { - if cursor.match_all(&[Lt, Lifetime, Gt, CaptureIdent], &mut captures) { - match cursor.get_text(captures[0]) { - "LateLintPass" => context = Some("LateContext"), - "EarlyLintPass" => context = Some("EarlyContext"), - _ => {}, - } + "impl" if cursor.match_all(&[Lt, Lifetime, Gt, CaptureIdent], &mut captures) => { + match cursor.get_text(captures[0]) { + "LateLintPass" => context = Some("LateContext"), + "EarlyLintPass" => context = Some("EarlyContext"), + _ => {}, } }, _ => {}, diff --git a/src/tools/clippy/clippy_dev/src/parse.rs b/src/tools/clippy/clippy_dev/src/parse.rs index de5caf4e1ef65..ffb50784a9a75 100644 --- a/src/tools/clippy/clippy_dev/src/parse.rs +++ b/src/tools/clippy/clippy_dev/src/parse.rs @@ -2,9 +2,10 @@ pub mod cursor; use self::cursor::{Capture, Cursor}; use crate::utils::{ErrAction, File, Scoped, expect_action, walk_dir_no_dot_or_target}; -use core::fmt::{Display, Write as _}; +use core::fmt::{self, Display, Write as _}; use core::range::Range; use rustc_arena::DroplessArena; +use rustc_data_structures::fx::FxHashMap; use std::fs; use std::path::{self, Path, PathBuf}; use std::str::pattern::Pattern; @@ -81,8 +82,49 @@ impl StrBuf { } } -pub struct Lint<'cx> { +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub enum LintTool { + Rustc, + Clippy, +} +impl LintTool { + /// Gets the namespace prefix to use when naming a lint including the `::`. + pub fn prefix(self) -> &'static str { + match self { + Self::Rustc => "", + Self::Clippy => "clippy::", + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct LintName<'cx> { pub name: &'cx str, + pub tool: LintTool, +} +impl<'cx> LintName<'cx> { + pub fn new_rustc(name: &'cx str) -> Self { + Self { + name, + tool: LintTool::Rustc, + } + } + + pub fn new_clippy(name: &'cx str) -> Self { + Self { + name, + tool: LintTool::Clippy, + } + } +} +impl Display for LintName<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.tool.prefix())?; + f.write_str(self.name) + } +} + +pub struct ActiveLint<'cx> { pub group: &'cx str, pub module: &'cx str, pub path: PathBuf, @@ -90,22 +132,34 @@ pub struct Lint<'cx> { } pub struct DeprecatedLint<'cx> { - pub name: &'cx str, pub reason: &'cx str, pub version: &'cx str, } pub struct RenamedLint<'cx> { - pub old_name: &'cx str, - pub new_name: &'cx str, + pub new_name: LintName<'cx>, pub version: &'cx str, } +pub enum Lint<'cx> { + Active(ActiveLint<'cx>), + Deprecated(DeprecatedLint<'cx>), + Renamed(RenamedLint<'cx>), +} + +pub struct LintData<'cx> { + pub lints: FxHashMap<&'cx str, Lint<'cx>>, +} + impl<'cx> ParseCxImpl<'cx> { - /// Finds all lint declarations (`declare_clippy_lint!`) + /// Finds and parses all lint declarations. #[must_use] - pub fn find_lint_decls(&mut self) -> Vec> { - let mut lints = Vec::with_capacity(1000); + pub fn parse_lint_decls(&mut self) -> LintData<'cx> { + let mut data = LintData { + #[expect(clippy::default_trait_access)] + lints: FxHashMap::with_capacity_and_hasher(1000, Default::default()), + }; + let mut contents = String::new(); for e in expect_action(fs::read_dir("."), ErrAction::Read, ".") { let e = expect_action(e, ErrAction::Read, "."); @@ -143,17 +197,18 @@ impl<'cx> ParseCxImpl<'cx> { e.path(), File::open_read_to_cleared_string(e.path(), &mut contents), module, - &mut lints, + &mut data, ); } } } - lints.sort_by(|lhs, rhs| lhs.name.cmp(rhs.name)); - lints + + self.read_deprecated_lints(&mut data); + data } /// Parse a source file looking for `declare_clippy_lint` macro invocations. - fn parse_clippy_lint_decls(&mut self, path: &Path, contents: &str, module: &'cx str, lints: &mut Vec>) { + fn parse_clippy_lint_decls(&mut self, path: &Path, contents: &str, module: &'cx str, data: &mut LintData<'cx>) { #[allow(clippy::enum_glob_use)] use cursor::Pat::*; #[rustfmt::skip] @@ -170,19 +225,24 @@ impl<'cx> ParseCxImpl<'cx> { let mut captures = [Capture::EMPTY; 2]; while let Some(start) = cursor.find_ident("declare_clippy_lint") { if cursor.match_all(DECL_TOKENS, &mut captures) && cursor.find_pat(CloseBrace) { - lints.push(Lint { - name: self.str_buf.alloc_ascii_lower(self.arena, cursor.get_text(captures[0])), - group: self.arena.alloc_str(cursor.get_text(captures[1])), - module, - path: path.into(), - declaration_range: start as usize..cursor.pos() as usize, - }); + assert!( + data.lints + .insert( + self.str_buf.alloc_ascii_lower(self.arena, cursor.get_text(captures[0])), + Lint::Active(ActiveLint { + group: self.arena.alloc_str(cursor.get_text(captures[1])), + module, + path: path.into(), + declaration_range: start as usize..cursor.pos() as usize, + }), + ) + .is_none() + ); } } } - #[must_use] - pub fn read_deprecated_lints(&mut self) -> (Vec>, Vec>) { + fn read_deprecated_lints(&mut self, data: &mut LintData<'cx>) { #[allow(clippy::enum_glob_use)] use cursor::Pat::*; #[rustfmt::skip] @@ -204,8 +264,6 @@ impl<'cx> ParseCxImpl<'cx> { ]; let path = "clippy_lints/src/deprecated_lints.rs"; - let mut deprecated = Vec::with_capacity(30); - let mut renamed = Vec::with_capacity(80); let mut contents = String::new(); File::open_read_to_cleared_string(path, &mut contents); @@ -220,11 +278,17 @@ impl<'cx> ParseCxImpl<'cx> { if cursor.find_ident("declare_with_version").is_some() && cursor.match_all(DEPRECATED_TOKENS, &mut []) { while cursor.match_all(DECL_TOKENS, &mut captures) { - deprecated.push(DeprecatedLint { - name: self.parse_str_single_line(path.as_ref(), cursor.get_text(captures[1])), - reason: self.parse_str_single_line(path.as_ref(), cursor.get_text(captures[2])), - version: self.parse_str_single_line(path.as_ref(), cursor.get_text(captures[0])), - }); + assert!( + data.lints + .insert( + self.parse_clippy_lint_name(path.as_ref(), cursor.get_text(captures[1])), + Lint::Deprecated(DeprecatedLint { + reason: self.parse_str_single_line(path.as_ref(), cursor.get_text(captures[2])), + version: self.parse_str_single_line(path.as_ref(), cursor.get_text(captures[0])), + }), + ) + .is_none() + ); } } else { panic!("error reading deprecated lints"); @@ -232,19 +296,21 @@ impl<'cx> ParseCxImpl<'cx> { if cursor.find_ident("declare_with_version").is_some() && cursor.match_all(RENAMED_TOKENS, &mut []) { while cursor.match_all(DECL_TOKENS, &mut captures) { - renamed.push(RenamedLint { - old_name: self.parse_str_single_line(path.as_ref(), cursor.get_text(captures[1])), - new_name: self.parse_str_single_line(path.as_ref(), cursor.get_text(captures[2])), - version: self.parse_str_single_line(path.as_ref(), cursor.get_text(captures[0])), - }); + assert!( + data.lints + .insert( + self.parse_clippy_lint_name(path.as_ref(), cursor.get_text(captures[1])), + Lint::Renamed(RenamedLint { + new_name: self.parse_lint_name(path.as_ref(), cursor.get_text(captures[2])), + version: self.parse_str_single_line(path.as_ref(), cursor.get_text(captures[0])), + }), + ) + .is_none() + ); } } else { panic!("error reading renamed lints"); } - - deprecated.sort_by(|lhs, rhs| lhs.name.cmp(rhs.name)); - renamed.sort_by(|lhs, rhs| lhs.old_name.cmp(rhs.old_name)); - (deprecated, renamed) } /// Removes the line splices and surrounding quotes from a string literal @@ -282,4 +348,23 @@ impl<'cx> ParseCxImpl<'cx> { ); value } + + fn parse_clippy_lint_name(&mut self, path: &Path, s: &str) -> &'cx str { + match self.parse_str_single_line(path, s).strip_prefix("clippy::") { + Some(x) => x, + None => panic!( + "error parsing `{}`: `{s}` should be a string starting with `clippy::`", + path.display() + ), + } + } + + fn parse_lint_name(&mut self, path: &Path, s: &str) -> LintName<'cx> { + let s = self.parse_str_single_line(path, s); + let (name, tool) = match s.strip_prefix("clippy::") { + Some(s) => (s, LintTool::Clippy), + None => (s, LintTool::Rustc), + }; + LintName { name, tool } + } } diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs index 3d0da68461144..a4cf15058986b 100644 --- a/src/tools/clippy/clippy_dev/src/update_lints.rs +++ b/src/tools/clippy/clippy_dev/src/update_lints.rs @@ -1,5 +1,5 @@ use crate::parse::cursor::Cursor; -use crate::parse::{DeprecatedLint, Lint, ParseCx, RenamedLint}; +use crate::parse::{Lint, LintData, ParseCx}; use crate::utils::{FileUpdater, UpdateMode, UpdateStatus, update_text_region_fn}; use itertools::Itertools; use std::collections::HashSet; @@ -22,55 +22,62 @@ const DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.ht /// /// Panics if a file path could not read from or then written to pub fn update(cx: ParseCx<'_>, update_mode: UpdateMode) { - let lints = cx.find_lint_decls(); - let (deprecated, renamed) = cx.read_deprecated_lints(); - generate_lint_files(update_mode, &lints, &deprecated, &renamed); + let data = cx.parse_lint_decls(); + generate_lint_files(update_mode, &data); } #[expect(clippy::too_many_lines)] -pub fn generate_lint_files( - update_mode: UpdateMode, - lints: &[Lint<'_>], - deprecated: &[DeprecatedLint<'_>], - renamed: &[RenamedLint<'_>], -) { +pub fn generate_lint_files(update_mode: UpdateMode, data: &LintData<'_>) { let mut updater = FileUpdater::default(); + + let mut lints: Vec<_> = data.lints.iter().map(|(&x, y)| (x, y)).collect(); + lints.sort_by_key(|&(x, _)| x); updater.update_file_checked( "cargo dev update_lints", update_mode, - "README.md", - &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| { - write!(dst, "{}", round_to_fifty(lints.len())).unwrap(); - }), + "CHANGELOG.md", + &mut update_text_region_fn( + "\n", + "", + |dst| { + for &(lint, _) in &lints { + writeln!(dst, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap(); + } + }, + ), ); + + let mut active = Vec::with_capacity(lints.len()); + let mut deprecated = Vec::with_capacity(lints.len() / 8); + let mut renamed = Vec::with_capacity(lints.len() / 8); + for &(name, lint) in &lints { + match lint { + Lint::Active(lint) => active.push((name, lint)), + Lint::Deprecated(lint) => deprecated.push((name, lint)), + Lint::Renamed(lint) => renamed.push((name, lint)), + } + } + active.sort_by_key(|&(_, lint)| lint.module); + + // Round to avoid updating the readme every time a lint is added/deprecated. + let lint_count = active.len() / 50 * 50; updater.update_file_checked( "cargo dev update_lints", update_mode, - "book/src/README.md", + "README.md", &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| { - write!(dst, "{}", round_to_fifty(lints.len())).unwrap(); + write!(dst, "{lint_count}").unwrap(); }), ); updater.update_file_checked( "cargo dev update_lints", update_mode, - "CHANGELOG.md", - &mut update_text_region_fn( - "\n", - "", - |dst| { - for lint in lints - .iter() - .map(|l| l.name) - .chain(deprecated.iter().filter_map(|l| l.name.strip_prefix("clippy::"))) - .chain(renamed.iter().filter_map(|l| l.old_name.strip_prefix("clippy::"))) - .sorted() - { - writeln!(dst, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap(); - } - }, - ), + "book/src/README.md", + &mut update_text_region_fn("[There are over ", " lints included in this crate!]", |dst| { + write!(dst, "{lint_count}").unwrap(); + }), ); + updater.update_file_checked( "cargo dev update_lints", update_mode, @@ -84,11 +91,11 @@ pub fn generate_lint_files( ); dst.push_str(&src[..cursor.pos() as usize]); dst.push_str("! { DEPRECATED(DEPRECATED_VERSION) = [\n"); - for lint in deprecated { + for &(name, data) in &deprecated { write!( dst, - " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n", - lint.version, lint.name, lint.reason, + " #[clippy::version = \"{}\"]\n (\"clippy::{name}\", \"{}\"),\n", + data.version, data.reason, ) .unwrap(); } @@ -98,11 +105,11 @@ pub fn generate_lint_files( declare_with_version! { RENAMED(RENAMED_VERSION) = [\n\ ", ); - for lint in renamed { + for &(name, data) in &renamed { write!( dst, - " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n", - lint.version, lint.old_name, lint.new_name, + " #[clippy::version = \"{}\"]\n (\"clippy::{name}\", \"{}\"),\n", + data.version, data.new_name, ) .unwrap(); } @@ -116,8 +123,8 @@ pub fn generate_lint_files( "tests/ui/deprecated.rs", &mut |_, src, dst| { dst.push_str(GENERATED_FILE_COMMENT); - for lint in deprecated { - writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.name, lint.name).unwrap(); + for &(lint, _) in &deprecated { + writeln!(dst, "#![warn(clippy::{lint})] //~ ERROR: lint `clippy::{lint}`").unwrap(); } dst.push_str("\nfn main() {}\n"); UpdateStatus::from_changed(src != dst) @@ -131,25 +138,25 @@ pub fn generate_lint_files( let mut seen_lints = HashSet::new(); dst.push_str(GENERATED_FILE_COMMENT); dst.push_str("#![allow(clippy::duplicated_attributes)]\n"); - for lint in renamed { + for &(_, lint) in &renamed { if seen_lints.insert(lint.new_name) { writeln!(dst, "#![allow({})]", lint.new_name).unwrap(); } } - seen_lints.clear(); - for lint in renamed { - if seen_lints.insert(lint.old_name) { - writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap(); - } + for &(lint, _) in &renamed { + writeln!(dst, "#![warn(clippy::{lint})] //~ ERROR: lint `clippy::{lint}`").unwrap(); } dst.push_str("\nfn main() {}\n"); UpdateStatus::from_changed(src != dst) }, ); - for (crate_name, lints) in lints.iter().into_group_map_by(|&l| { - let Some(path::Component::Normal(name)) = l.path.components().next() else { + for (crate_name, lints) in active.iter().copied().into_group_map_by(|&(_, lint)| { + let Some(path::Component::Normal(name)) = lint.path.components().next() else { // All paths should start with `{crate_name}/src` when parsed from `find_lint_decls` - panic!("internal error: can't read crate name from path `{}`", l.path.display()); + panic!( + "internal error: can't read crate name from path `{}`", + lint.path.display() + ); }; name }) { @@ -161,14 +168,12 @@ pub fn generate_lint_files( "// begin lints modules, do not remove this comment, it's used in `update_lints`\n", "// end lints modules, do not remove this comment, it's used in `update_lints`", |dst| { - for lint_mod in lints - .iter() - .filter(|l| !l.module.is_empty()) - .map(|l| l.module.split_once("::").map_or(l.module, |x| x.0)) - .sorted() - .dedup() - { - writeln!(dst, "mod {lint_mod};").unwrap(); + let mut prev = ""; + for &(_, lint) in &lints { + if lint.module != prev { + writeln!(dst, "mod {};", lint.module).unwrap(); + prev = lint.module; + } } }, ), @@ -180,11 +185,15 @@ pub fn generate_lint_files( &mut |_, src, dst| { dst.push_str(GENERATED_FILE_COMMENT); dst.push_str("pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[\n"); - for (module_path, lint_name) in lints.iter().map(|l| (&l.module, l.name.to_uppercase())).sorted() { - if module_path.is_empty() { - writeln!(dst, " crate::{lint_name}_INFO,").unwrap(); + let mut buf = String::new(); + for &(name, lint) in &lints { + buf.clear(); + buf.push_str(name); + buf.make_ascii_uppercase(); + if lint.module.is_empty() { + writeln!(dst, " crate::{buf}_INFO,").unwrap(); } else { - writeln!(dst, " crate::{module_path}::{lint_name}_INFO,").unwrap(); + writeln!(dst, " crate::{}::{buf}_INFO,", lint.module).unwrap(); } } dst.push_str("];\n"); @@ -193,7 +202,3 @@ pub fn generate_lint_files( ); } } - -fn round_to_fifty(count: usize) -> usize { - count / 50 * 50 -} diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs index cc62306b33b53..d48ef10c8cd25 100644 --- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs +++ b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::macros::{PanicExpn, find_assert_args, root_macro_call_first_node}; +use clippy_utils::macros::{find_assert_args, root_macro_call_first_node}; use clippy_utils::res::{MaybeDef, MaybeResPath}; use clippy_utils::source::snippet_with_context; use clippy_utils::sym; @@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { if let Some(macro_call) = root_macro_call_first_node(cx, e) && matches!(cx.tcx.get_diagnostic_name(macro_call.def_id), Some(sym::assert_macro)) && let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) - && matches!(panic_expn, PanicExpn::Empty) + && panic_expn.is_default_message() && let ExprKind::MethodCall(method_segment, recv, [], _) = condition.kind && let result_type_with_refs = cx.typeck_results().expr_ty(recv) && let result_type = result_type_with_refs.peel_refs() diff --git a/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs b/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs index bd6459d6f9dbc..e3b1a05bda7dd 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs @@ -2,13 +2,14 @@ use super::DEPRECATED_SEMVER; use clippy_utils::diagnostics::span_lint; use clippy_utils::sym; use rustc_ast::{LitKind, MetaItemLit}; +use rustc_hir::VERSION_PLACEHOLDER; use rustc_lint::EarlyContext; use rustc_span::Span; use semver::Version; pub(super) fn check(cx: &EarlyContext<'_>, span: Span, lit: &MetaItemLit) { if let LitKind::Str(is, _) = lit.kind - && (is == sym::TBD || Version::parse(is.as_str()).is_ok()) + && (is == sym::TBD || is.as_str() == VERSION_PLACEHOLDER || Version::parse(is.as_str()).is_ok()) { return; } diff --git a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs index 70c9c45a60c89..947b99696bb1f 100644 --- a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs +++ b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs @@ -2,7 +2,10 @@ use crate::reference::DEREF_ADDROF; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; -use clippy_utils::{get_parent_expr, is_expr_temporary_value, is_from_proc_macro, is_lint_allowed, is_mutable}; +use clippy_utils::{ + get_enclosing_closure, get_parent_expr, is_expr_temporary_value, is_from_proc_macro, is_lint_allowed, is_mutable, + is_upvar_in_closure, path_to_local_with_projections, +}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Node, UnOp}; use rustc_lint::{LateContext, LateLintPass}; @@ -81,6 +84,16 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { && (is_expr_temporary_value(cx, deref_target) || !potentially_bound_to_mutable_ref(cx, e)) && let Some(deref_text) = deref_target.span.get_source_text(cx) { + // `&*x` can be needed to shorten the borrow of `x`. Replacing it with `x` can be + // incorrect when `x` is a closure-captured upvar (e.g. a closure returning another + // closure that captures `x`). + if let Some(closure) = get_enclosing_closure(cx, e.hir_id) + && let Some(local_id) = path_to_local_with_projections(deref_target) + && is_upvar_in_closure(cx, closure, local_id) + { + return; + } + span_lint_and_then( cx, BORROW_DEREF_REF, diff --git a/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs b/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs index 80514cb52e6e4..e92e3d115b17c 100644 --- a/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs +++ b/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs @@ -9,7 +9,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, ignore_publish: b for package in &metadata.packages { // only run the lint if publish is `None` (`publish = true` or skipped entirely) // or if the vector isn't empty (`publish = ["something"]`) - if package.publish.as_ref().filter(|publish| publish.is_empty()).is_none() || ignore_publish { + if package.publish.as_ref().is_none_or(|publish| !publish.is_empty()) || ignore_publish { if is_empty_str(package.description.as_ref()) { missing_warning(cx, package, "package.description"); } diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs index 8b0859722b138..5cc41c121965e 100644 --- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::numeric_literal::NumericLiteral; -use clippy_utils::res::MaybeResPath; +use clippy_utils::res::MaybeResPath as _; use clippy_utils::source::{SpanRangeExt, snippet_opt}; use clippy_utils::visitors::{Visitable, for_each_expr_without_closures}; use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, sym}; use rustc_ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Expr, ExprKind, Lit, Node, Path, QPath, TyKind, UnOp}; +use rustc_hir::{Expr, ExprKind, FnRetTy, Lit, Node, Path, QPath, TyKind, UnOp}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, FloatTy, InferTy, Ty}; @@ -39,10 +39,8 @@ pub(super) fn check<'tcx>( // Ignore casts to pointers that are aliases or cfg dependant, e.g. // - p as *const std::ffi::c_char (alias) // - p as *const std::os::raw::c_char (cfg dependant) - TyKind::Path(qpath) => { - if is_ty_alias(&qpath) || is_hir_ty_cfg_dependant(cx, to_pointee.ty) { - return false; - } + TyKind::Path(qpath) if is_ty_alias(&qpath) || is_hir_ty_cfg_dependant(cx, to_pointee.ty) => { + return false; }, // Ignore `p as *const _` TyKind::Infer(()) => return false, @@ -97,7 +95,7 @@ pub(super) fn check<'tcx>( // skip cast of fn call that returns type alias if let ExprKind::Cast(inner, ..) = expr.kind - && is_cast_from_ty_alias(cx, inner, cast_from) + && is_cast_from_ty_alias(cx, inner) { return false; } @@ -270,34 +268,25 @@ fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 { /// Finds whether an `Expr` returns a type alias. /// -/// TODO: Maybe we should move this to `clippy_utils` so others won't need to go down this dark, -/// dark path reimplementing this (or something similar). -fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx>, cast_from: Ty<'tcx>) -> bool { +/// When in doubt, for example because it calls a non-local function that we don't have the +/// declaration for, assume if might be a type alias. +fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx>) -> bool { for_each_expr_without_closures(expr, |expr| { // Calls are a `Path`, and usage of locals are a `Path`. So, this checks // - call() as i32 // - local as i32 if let ExprKind::Path(qpath) = expr.kind { let res = cx.qpath_res(&qpath, expr.hir_id); - // Function call if let Res::Def(DefKind::Fn, def_id) = res { - let Some(snippet) = cx.tcx.def_span(def_id).get_source_text(cx) else { - return ControlFlow::Continue(()); + let Some(def_id) = def_id.as_local() else { + // External function, we can't know, better be safe + return ControlFlow::Break(()); }; - // This is the worst part of this entire function. This is the only way I know of to - // check whether a function returns a type alias. Sure, you can get the return type - // from a function in the current crate as an hir ty, but how do you get it for - // external functions?? Simple: It's impossible. So, we check whether a part of the - // function's declaration snippet is exactly equal to the `Ty`. That way, we can - // see whether it's a type alias. - // - // FIXME: This won't work if the type is given an alias through `use`, should we - // consider this a type alias as well? - if !snippet - .split("->") - .skip(1) - .any(|s| snippet_eq_ty(s, cast_from) || s.split("where").any(|ty| snippet_eq_ty(ty, cast_from))) + if let Some(FnRetTy::Return(ty)) = cx.tcx.hir_get_fn_output(def_id) + && let TyKind::Path(qpath) = ty.kind + && is_ty_alias(&qpath) { + // Function call to a local function returning a type alias return ControlFlow::Break(()); } // Local usage @@ -305,7 +294,7 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx && let Node::LetStmt(l) = cx.tcx.parent_hir_node(hir_id) { if let Some(e) = l.init - && is_cast_from_ty_alias(cx, e, cast_from) + && is_cast_from_ty_alias(cx, e) { return ControlFlow::Break::<()>(()); } @@ -323,7 +312,3 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx }) .is_some() } - -fn snippet_eq_ty(snippet: &str, ty: Ty<'_>) -> bool { - snippet.trim() == ty.to_string() || snippet.trim().contains(&format!("::{ty}")) -} diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index dfc1ca107feb2..c256ad9b06a4e 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -81,10 +81,8 @@ impl CognitiveComplexity { } cc += arms.iter().filter(|arm| arm.guard.is_some()).count() as u64; }, - ExprKind::Ret(_) => { - if !matches!(prev_expr, Some(ExprKind::Ret(_))) { - returns += 1; - } + ExprKind::Ret(_) if !matches!(prev_expr, Some(ExprKind::Ret(_))) => { + returns += 1; }, _ => {}, } diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs index be07ce1272bd8..17e11b8b281d9 100644 --- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs +++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs @@ -307,7 +307,7 @@ fn expr_block<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> { } /// If the expression is a `||`, suggest parentheses around it. -fn parens_around(expr: &Expr<'_>) -> Vec<(Span, String)> { +pub(super) fn parens_around(expr: &Expr<'_>) -> Vec<(Span, String)> { if let ExprKind::Binary(op, _, _) = expr.peel_drop_temps().kind && op.node == BinOpKind::Or { @@ -334,7 +334,7 @@ fn span_extract_keyword(sm: &SourceMap, span: Span, keyword: &str) -> Option (Span, Span, Span) { +pub(super) fn peel_parens(sm: &SourceMap, mut span: Span) -> (Span, Span, Span) { use crate::rustc_span::Pos; let start = span.shrink_to_lo(); diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index a04d133b0d726..e16b194c0cad8 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -100,11 +100,12 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::dereference::NEEDLESS_BORROW_INFO, crate::dereference::REF_BINDING_TO_REFERENCE_INFO, crate::derivable_impls::DERIVABLE_IMPLS_INFO, - crate::derive::DERIVED_HASH_WITH_MANUAL_EQ_INFO, crate::derive::DERIVE_ORD_XOR_PARTIAL_ORD_INFO, crate::derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ_INFO, + crate::derive::DERIVED_HASH_WITH_MANUAL_EQ_INFO, crate::derive::EXPL_IMPL_CLONE_ON_COPY_INFO, crate::derive::UNSAFE_DERIVE_DESERIALIZE_INFO, + crate::disallowed_fields::DISALLOWED_FIELDS_INFO, crate::disallowed_macros::DISALLOWED_MACROS_INFO, crate::disallowed_methods::DISALLOWED_METHODS_INFO, crate::disallowed_names::DISALLOWED_NAMES_INFO, @@ -173,6 +174,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::format_args::TO_STRING_IN_FORMAT_ARGS_INFO, crate::format_args::UNINLINED_FORMAT_ARGS_INFO, crate::format_args::UNNECESSARY_DEBUG_FORMATTING_INFO, + crate::format_args::UNNECESSARY_TRAILING_COMMA_INFO, crate::format_args::UNUSED_FORMAT_SPECS_INFO, crate::format_impl::PRINT_IN_FORMAT_IMPL_INFO, crate::format_impl::RECURSIVE_FORMAT_IMPL_INFO, @@ -204,8 +206,8 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::if_not_else::IF_NOT_ELSE_INFO, crate::if_then_some_else_none::IF_THEN_SOME_ELSE_NONE_INFO, crate::ifs::BRANCHES_SHARING_CODE_INFO, - crate::ifs::IFS_SAME_COND_INFO, crate::ifs::IF_SAME_THEN_ELSE_INFO, + crate::ifs::IFS_SAME_COND_INFO, crate::ifs::SAME_FUNCTIONS_IN_IF_CONDITION_INFO, crate::ignored_unit_patterns::IGNORED_UNIT_PATTERNS_INFO, crate::impl_hash_with_borrow_str_and_bytes::IMPL_HASH_BORROW_WITH_STR_AND_BYTES_INFO, @@ -336,8 +338,8 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::matches::MATCH_SAME_ARMS_INFO, crate::matches::MATCH_SINGLE_BINDING_INFO, crate::matches::MATCH_STR_CASE_MISMATCH_INFO, - crate::matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS_INFO, crate::matches::MATCH_WILD_ERR_ARM_INFO, + crate::matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS_INFO, crate::matches::NEEDLESS_MATCH_INFO, crate::matches::REDUNDANT_GUARDS_INFO, crate::matches::REDUNDANT_PATTERN_MATCHING_INFO, @@ -359,9 +361,9 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::methods::CHARS_LAST_CMP_INFO, crate::methods::CHARS_NEXT_CMP_INFO, crate::methods::CLEAR_WITH_DRAIN_INFO, - crate::methods::CLONED_INSTEAD_OF_COPIED_INFO, crate::methods::CLONE_ON_COPY_INFO, crate::methods::CLONE_ON_REF_PTR_INFO, + crate::methods::CLONED_INSTEAD_OF_COPIED_INFO, crate::methods::COLLAPSIBLE_STR_REPLACE_INFO, crate::methods::CONST_IS_EMPTY_INFO, crate::methods::DOUBLE_ENDED_ITERATOR_LAST_INFO, @@ -389,7 +391,6 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::methods::IO_OTHER_ERROR_INFO, crate::methods::IP_CONSTANT_INFO, crate::methods::IS_DIGIT_ASCII_RADIX_INFO, - crate::methods::ITERATOR_STEP_BY_ZERO_INFO, crate::methods::ITER_CLONED_COLLECT_INFO, crate::methods::ITER_COUNT_INFO, crate::methods::ITER_FILTER_IS_OK_INFO, @@ -405,10 +406,11 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::methods::ITER_SKIP_NEXT_INFO, crate::methods::ITER_SKIP_ZERO_INFO, crate::methods::ITER_WITH_DRAIN_INFO, + crate::methods::ITERATOR_STEP_BY_ZERO_INFO, crate::methods::JOIN_ABSOLUTE_PATHS_INFO, crate::methods::LINES_FILTER_MAP_OK_INFO, - crate::methods::MANUAL_CONTAINS_INFO, crate::methods::MANUAL_C_STR_LITERALS_INFO, + crate::methods::MANUAL_CONTAINS_INFO, crate::methods::MANUAL_FILTER_MAP_INFO, crate::methods::MANUAL_FIND_MAP_INFO, crate::methods::MANUAL_INSPECT_INFO, @@ -437,8 +439,8 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::methods::NEEDLESS_OPTION_TAKE_INFO, crate::methods::NEEDLESS_SPLITN_INFO, crate::methods::NEW_RET_NO_SELF_INFO, - crate::methods::NONSENSICAL_OPEN_OPTIONS_INFO, crate::methods::NO_EFFECT_REPLACE_INFO, + crate::methods::NONSENSICAL_OPEN_OPTIONS_INFO, crate::methods::OBFUSCATED_IF_ELSE_INFO, crate::methods::OK_EXPECT_INFO, crate::methods::OPTION_AS_REF_CLONED_INFO, @@ -452,8 +454,8 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::methods::PTR_OFFSET_BY_LITERAL_INFO, crate::methods::PTR_OFFSET_WITH_CAST_INFO, crate::methods::RANGE_ZIP_WITH_LEN_INFO, - crate::methods::READONLY_WRITE_LOCK_INFO, crate::methods::READ_LINE_WITHOUT_TRIM_INFO, + crate::methods::READONLY_WRITE_LOCK_INFO, crate::methods::REDUNDANT_AS_STR_INFO, crate::methods::REDUNDANT_ITER_CLONED_INFO, crate::methods::REPEAT_ONCE_INFO, @@ -468,9 +470,9 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::methods::SKIP_WHILE_NEXT_INFO, crate::methods::SLICED_STRING_AS_BYTES_INFO, crate::methods::STABLE_SORT_PRIMITIVE_INFO, + crate::methods::STR_SPLIT_AT_NEWLINE_INFO, crate::methods::STRING_EXTEND_CHARS_INFO, crate::methods::STRING_LIT_CHARS_ANY_INFO, - crate::methods::STR_SPLIT_AT_NEWLINE_INFO, crate::methods::SUSPICIOUS_COMMAND_ARG_SPACE_INFO, crate::methods::SUSPICIOUS_MAP_INFO, crate::methods::SUSPICIOUS_OPEN_OPTIONS_INFO, @@ -641,8 +643,8 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::ranges::RANGE_MINUS_ONE_INFO, crate::ranges::RANGE_PLUS_ONE_INFO, crate::ranges::REVERSED_EMPTY_RANGES_INFO, - crate::raw_strings::NEEDLESS_RAW_STRINGS_INFO, crate::raw_strings::NEEDLESS_RAW_STRING_HASHES_INFO, + crate::raw_strings::NEEDLESS_RAW_STRINGS_INFO, crate::rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT_INFO, crate::read_zero_byte_vec::READ_ZERO_BYTE_VEC_INFO, crate::redundant_async_block::REDUNDANT_ASYNC_BLOCK_INFO, @@ -695,12 +697,12 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::std_instead_of_core::STD_INSTEAD_OF_CORE_INFO, crate::string_patterns::MANUAL_PATTERN_CHAR_COMPARISON_INFO, crate::string_patterns::SINGLE_CHAR_PATTERN_INFO, + crate::strings::STR_TO_STRING_INFO, crate::strings::STRING_ADD_INFO, crate::strings::STRING_ADD_ASSIGN_INFO, crate::strings::STRING_FROM_UTF8_AS_BYTES_INFO, crate::strings::STRING_LIT_AS_BYTES_INFO, crate::strings::STRING_SLICE_INFO, - crate::strings::STR_TO_STRING_INFO, crate::strings::TRIM_SPLIT_WHITESPACE_INFO, crate::strlen_on_c_strings::STRLEN_ON_C_STRINGS_INFO, crate::suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS_INFO, @@ -724,7 +726,6 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::transmute::CROSSPOINTER_TRANSMUTE_INFO, crate::transmute::EAGER_TRANSMUTE_INFO, crate::transmute::MISSING_TRANSMUTE_ANNOTATIONS_INFO, - crate::transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS_INFO, crate::transmute::TRANSMUTE_BYTES_TO_STR_INFO, crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO, crate::transmute::TRANSMUTE_INT_TO_NON_ZERO_INFO, @@ -732,6 +733,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO, crate::transmute::TRANSMUTE_PTR_TO_REF_INFO, crate::transmute::TRANSMUTE_UNDEFINED_REPR_INFO, + crate::transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS_INFO, crate::transmute::TRANSMUTING_NULL_INFO, crate::transmute::UNSOUND_COLLECTION_TRANSMUTE_INFO, crate::transmute::USELESS_TRANSMUTE_INFO, @@ -789,20 +791,20 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::useless_vec::USELESS_VEC_INFO, crate::vec_init_then_push::VEC_INIT_THEN_PUSH_INFO, crate::visibility::NEEDLESS_PUB_SELF_INFO, - crate::visibility::PUB_WITHOUT_SHORTHAND_INFO, crate::visibility::PUB_WITH_SHORTHAND_INFO, + crate::visibility::PUB_WITHOUT_SHORTHAND_INFO, crate::volatile_composites::VOLATILE_COMPOSITES_INFO, crate::wildcard_imports::ENUM_GLOB_USE_INFO, crate::wildcard_imports::WILDCARD_IMPORTS_INFO, - crate::write::PRINTLN_EMPTY_STRING_INFO, crate::write::PRINT_LITERAL_INFO, crate::write::PRINT_STDERR_INFO, crate::write::PRINT_STDOUT_INFO, crate::write::PRINT_WITH_NEWLINE_INFO, + crate::write::PRINTLN_EMPTY_STRING_INFO, crate::write::USE_DEBUG_INFO, - crate::write::WRITELN_EMPTY_STRING_INFO, crate::write::WRITE_LITERAL_INFO, crate::write::WRITE_WITH_NEWLINE_INFO, + crate::write::WRITELN_EMPTY_STRING_INFO, crate::zero_div_zero::ZERO_DIVIDED_BY_ZERO_INFO, crate::zero_repeat_side_effects::ZERO_REPEAT_SIDE_EFFECTS_INFO, crate::zero_sized_map_values::ZERO_SIZED_MAP_VALUES_INFO, diff --git a/src/tools/clippy/clippy_lints/src/disallowed_fields.rs b/src/tools/clippy/clippy_lints/src/disallowed_fields.rs new file mode 100644 index 0000000000000..f1136556e2ed8 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/disallowed_fields.rs @@ -0,0 +1,160 @@ +use clippy_config::Conf; +use clippy_config::types::{DisallowedPath, create_disallowed_map}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::paths::PathNS; +use clippy_utils::ty::get_field_def_id_by_name; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::DefIdMap; +use rustc_hir::{Expr, ExprKind, Pat, PatKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::TyCtxt; +use rustc_session::impl_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// Denies the configured fields in clippy.toml + /// + /// Note: Even though this lint is warn-by-default, it will only trigger if + /// fields are defined in the clippy.toml file. + /// + /// ### Why is this bad? + /// Some fields are undesirable in certain contexts, and it's beneficial to + /// lint for them as needed. + /// + /// ### Example + /// An example clippy.toml configuration: + /// ```toml + /// # clippy.toml + /// disallowed-fields = [ + /// # Can use a string as the path of the disallowed field. + /// "std::ops::Range::start", + /// # Can also use an inline table with a `path` key. + /// { path = "std::ops::Range::start" }, + /// # When using an inline table, can add a `reason` for why the field + /// # is disallowed. + /// { path = "std::ops::Range::start", reason = "The start of the range is not used" }, + /// ] + /// ``` + /// + /// ```rust + /// use std::ops::Range; + /// + /// let range = Range { start: 0, end: 1 }; + /// println!("{}", range.start); // `start` is disallowed in the config. + /// ``` + /// + /// Use instead: + /// ```rust + /// use std::ops::Range; + /// + /// let range = Range { start: 0, end: 1 }; + /// println!("{}", range.end); // `end` is _not_ disallowed in the config. + /// ``` + #[clippy::version = "1.93.0"] + pub DISALLOWED_FIELDS, + style, + "declaration of a disallowed field use" +} + +pub struct DisallowedFields { + disallowed: DefIdMap<(&'static str, &'static DisallowedPath)>, +} + +impl DisallowedFields { + pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { + let (disallowed, _) = create_disallowed_map( + tcx, + &conf.disallowed_fields, + PathNS::Field, + |def_kind| matches!(def_kind, DefKind::Field), + "field", + false, + ); + Self { disallowed } + } +} + +impl_lint_pass!(DisallowedFields => [DISALLOWED_FIELDS]); + +impl<'tcx> LateLintPass<'tcx> for DisallowedFields { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + let (id, span) = match &expr.kind { + ExprKind::Path(path) if let Res::Def(_, id) = cx.qpath_res(path, expr.hir_id) => (id, expr.span), + ExprKind::Field(e, ident) => { + // Very round-about way to get the field `DefId` from the expr: first we get its + // parent `Ty`. Then we go through all its fields to find the one with the expected + // name and get the `DefId` from it. + if let Some(parent_ty) = cx.typeck_results().expr_ty_adjusted_opt(e) + && let Some(field_def_id) = get_field_def_id_by_name(parent_ty, ident.name) + { + (field_def_id, ident.span) + } else { + return; + } + }, + _ => return, + }; + if let Some(&(path, disallowed_path)) = self.disallowed.get(&id) { + span_lint_and_then( + cx, + DISALLOWED_FIELDS, + span, + format!("use of a disallowed field `{path}`"), + disallowed_path.diag_amendment(span), + ); + } + } + + fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { + let PatKind::Struct(struct_path, pat_fields, _) = pat.kind else { + return; + }; + match cx.typeck_results().qpath_res(&struct_path, pat.hir_id) { + Res::Def(DefKind::Struct, struct_def_id) => { + let adt_def = cx.tcx.adt_def(struct_def_id); + for field in pat_fields { + if let Some(def_id) = adt_def.all_fields().find_map(|adt_field| { + if field.ident.name == adt_field.name { + Some(adt_field.did) + } else { + None + } + }) && let Some(&(path, disallowed_path)) = self.disallowed.get(&def_id) + { + span_lint_and_then( + cx, + DISALLOWED_FIELDS, + field.span, + format!("use of a disallowed field `{path}`"), + disallowed_path.diag_amendment(field.span), + ); + } + } + }, + Res::Def(DefKind::Variant, variant_def_id) => { + let enum_def_id = cx.tcx.parent(variant_def_id); + let variant = cx.tcx.adt_def(enum_def_id).variant_with_id(variant_def_id); + + for field in pat_fields { + if let Some(def_id) = variant.fields.iter().find_map(|adt_field| { + if field.ident.name == adt_field.name { + Some(adt_field.did) + } else { + None + } + }) && let Some(&(path, disallowed_path)) = self.disallowed.get(&def_id) + { + span_lint_and_then( + cx, + DISALLOWED_FIELDS, + field.span, + format!("use of a disallowed field `{path}`"), + disallowed_path.diag_amendment(field.span), + ); + } + } + }, + _ => {}, + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index e7a984694831b..0a2871f23964d 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -763,19 +763,11 @@ impl<'tcx> LateLintPass<'tcx> for Documentation { self.check_private_items, ); match item.kind { - ItemKind::Fn { sig, body, .. } => { + ItemKind::Fn { sig, body, .. } if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) - || item.span.in_external_macro(cx.tcx.sess.source_map())) - { - missing_headers::check( - cx, - item.owner_id, - sig, - headers, - Some(body), - self.check_private_items, - ); - } + || item.span.in_external_macro(cx.tcx.sess.source_map())) => + { + missing_headers::check(cx, item.owner_id, sig, headers, Some(body), self.check_private_items); }, ItemKind::Trait(_, _, unsafety, ..) => match (headers.safety, unsafety) { (false, Safety::Unsafe) => span_lint( diff --git a/src/tools/clippy/clippy_lints/src/double_parens.rs b/src/tools/clippy/clippy_lints/src/double_parens.rs index 351d29d874327..acc3e4936e440 100644 --- a/src/tools/clippy/clippy_lints/src/double_parens.rs +++ b/src/tools/clippy/clippy_lints/src/double_parens.rs @@ -46,28 +46,28 @@ impl EarlyLintPass for DoubleParens { // ((..)) // ^^^^^^ expr // ^^^^ inner - ExprKind::Paren(inner) if matches!(inner.kind, ExprKind::Paren(_) | ExprKind::Tup(_)) => { - if expr.span.eq_ctxt(inner.span) + ExprKind::Paren(inner) + if matches!(inner.kind, ExprKind::Paren(_) | ExprKind::Tup(_)) + && expr.span.eq_ctxt(inner.span) && !expr.span.in_external_macro(cx.sess().source_map()) - && check_source(cx, inner) - { - // suggest removing the outer parens + && check_source(cx, inner) => + { + // suggest removing the outer parens - let mut applicability = Applicability::MachineApplicable; - // We don't need to use `snippet_with_context` here, because: - // - if `inner`'s `ctxt` is from macro, we don't lint in the first place (see the check above) - // - otherwise, calling `snippet_with_applicability` on a not-from-macro span is fine - let sugg = snippet_with_applicability(cx.sess(), inner.span, "_", &mut applicability); - span_lint_and_sugg( - cx, - DOUBLE_PARENS, - expr.span, - "unnecessary parentheses", - "remove them", - sugg.to_string(), - applicability, - ); - } + let mut applicability = Applicability::MachineApplicable; + // We don't need to use `snippet_with_context` here, because: + // - if `inner`'s `ctxt` is from macro, we don't lint in the first place (see the check above) + // - otherwise, calling `snippet_with_applicability` on a not-from-macro span is fine + let sugg = snippet_with_applicability(cx.sess(), inner.span, "_", &mut applicability); + span_lint_and_sugg( + cx, + DOUBLE_PARENS, + expr.span, + "unnecessary parentheses", + "remove them", + sugg.to_string(), + applicability, + ); }, // func((n)) @@ -76,26 +76,24 @@ impl EarlyLintPass for DoubleParens { // ^ inner ExprKind::Call(_, args) | ExprKind::MethodCall(box MethodCall { args, .. }) if let [arg] = &**args - && let ExprKind::Paren(inner) = &arg.kind => - { - if expr.span.eq_ctxt(arg.span) + && let ExprKind::Paren(inner) = &arg.kind + && expr.span.eq_ctxt(arg.span) && !arg.span.in_external_macro(cx.sess().source_map()) - && check_source(cx, arg) - { - // suggest removing the inner parens + && check_source(cx, arg) => + { + // suggest removing the inner parens - let mut applicability = Applicability::MachineApplicable; - let sugg = snippet_with_context(cx.sess(), inner.span, arg.span.ctxt(), "_", &mut applicability).0; - span_lint_and_sugg( - cx, - DOUBLE_PARENS, - arg.span, - "unnecessary parentheses", - "remove them", - sugg.to_string(), - applicability, - ); - } + let mut applicability = Applicability::MachineApplicable; + let sugg = snippet_with_context(cx.sess(), inner.span, arg.span.ctxt(), "_", &mut applicability).0; + span_lint_and_sugg( + cx, + DOUBLE_PARENS, + arg.span, + "unnecessary parentheses", + "remove them", + sugg.to_string(), + applicability, + ); }, _ => {}, } diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index b4d2d99fd9ff4..d987a76f5394c 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -27,7 +27,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, DerefAdjustKind}; use rustc_middle::ty::{self, GenericArg, List, TraitRef, Ty, TyCtxt, Upcast}; use rustc_session::impl_lint_pass; use rustc_span::edition::Edition::Edition2021; -use rustc_span::{Span, Symbol}; +use rustc_span::{BytePos, Pos, Span, Symbol}; use rustc_trait_selection::infer::TyCtxtInferExt; use rustc_trait_selection::traits::{Obligation, ObligationCause, Selection, SelectionContext}; @@ -228,6 +228,35 @@ declare_clippy_lint! { "formatting a pointer" } +declare_clippy_lint! { + /// ### What it does + /// Suggests removing an unnecessary trailing comma before the closing parenthesis in + /// single-line macro invocations. + /// + /// ### Why is this bad? + /// The trailing comma is redundant and removing it is more consistent with how + /// `rustfmt` formats regular function calls. + /// + /// ### Known limitations + /// This lint currently only runs on format-like macros (e.g. `format!`, `println!`, + /// `write!`) because it relies on format-argument parsing; applying it to arbitrary + /// user macros could cause incorrect suggestions. It may be extended to other + /// macros in the future. Only single-line macro invocations are linted. + /// + /// ### Example + /// ```no_run + /// println!("Foo={}", 1,); + /// ``` + /// Use instead: + /// ```no_run + /// println!("Foo={}", 1); + /// ``` + #[clippy::version = "1.95.0"] + pub UNNECESSARY_TRAILING_COMMA, + pedantic, + "unnecessary trailing comma before closing parenthesis" +} + impl_lint_pass!(FormatArgs<'_> => [ FORMAT_IN_FORMAT_ARGS, TO_STRING_IN_FORMAT_ARGS, @@ -235,6 +264,7 @@ impl_lint_pass!(FormatArgs<'_> => [ UNNECESSARY_DEBUG_FORMATTING, UNUSED_FORMAT_SPECS, POINTER_FORMAT, + UNNECESSARY_TRAILING_COMMA, ]); #[expect(clippy::struct_field_names)] @@ -279,6 +309,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs<'tcx> { has_pointer_format: &mut self.has_pointer_format, }; + linter.check_trailing_comma(); linter.check_templates(); if self.msrv.meets(cx, msrvs::FORMAT_ARGS_CAPTURE) { @@ -301,6 +332,29 @@ struct FormatArgsExpr<'a, 'tcx> { } impl<'tcx> FormatArgsExpr<'_, 'tcx> { + /// Check if there is a comma after the last format macro arg. + fn check_trailing_comma(&self) { + let span = self.macro_call.span; + if let Some(src) = span.get_source_text(self.cx) + && let Some(src) = src.strip_suffix([')', ']', '}']) + && let src = src.trim_end_matches(|c: char| c.is_whitespace() && c != '\n') + && let Some(src) = src.strip_suffix(',') + && let src = src.trim_end_matches(|c: char| c.is_whitespace() && c != '\n') + && !src.ends_with('\n') + { + span_lint_and_sugg( + self.cx, + UNNECESSARY_TRAILING_COMMA, + span.with_lo(span.lo() + BytePos::from_usize(src.len())) + .with_hi(span.hi() - BytePos(1)), + "unnecessary trailing comma", + "remove the trailing comma", + String::new(), + Applicability::MachineApplicable, + ); + } + } + fn check_templates(&mut self) { for piece in &self.format_args.template { if let FormatArgsPiece::Placeholder(placeholder) = piece diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index b9f16f2a371a1..15f34169b0d85 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -1,3 +1,4 @@ +use clippy_utils::res::MaybeDef as _; use hir::FnSig; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -219,6 +220,13 @@ fn check_must_use_candidate<'tcx>( format!("#[must_use] \n{indent}"), Applicability::MachineApplicable, ); + if let Some(msg) = match return_ty(cx, item_id).opt_diag_name(cx) { + Some(sym::ControlFlow) => Some("`ControlFlow` as `C` when `B` is uninhabited"), + Some(sym::Result) => Some("`Result` as `T` when `E` is uninhabited"), + _ => None, + } { + diag.note(format!("a future version of Rust will treat {msg} wrt `#[must_use]`")); + } }); } diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs index 8f6de9fc60bdd..8b0a4b4d78d9a 100644 --- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs +++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs @@ -252,10 +252,8 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { } } }, - ExprKind::Binary(op, l, r) => { - if op.node.is_comparison() { - return is_infinite(cx, l).and(is_infinite(cx, r)).and(MaybeInfinite); - } + ExprKind::Binary(op, l, r) if op.node.is_comparison() => { + return is_infinite(cx, l).and(is_infinite(cx, r)).and(MaybeInfinite); }, // TODO: ExprKind::Loop + Match _ => (), } diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 653c1cc7280f5..4dca8dfe94d09 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -103,6 +103,7 @@ mod default_union_representation; mod dereference; mod derivable_impls; mod derive; +mod disallowed_fields; mod disallowed_macros; mod disallowed_methods; mod disallowed_names; @@ -857,6 +858,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co Box::new(|_| Box::new(toplevel_ref_arg::ToplevelRefArg)), Box::new(|_| Box::new(volatile_composites::VolatileComposites)), Box::new(|_| Box::::default()), + Box::new(move |tcx| Box::new(disallowed_fields::DisallowedFields::new(tcx, conf))), Box::new(move |_| Box::new(manual_ilog2::ManualIlog2::new(conf))), Box::new(|_| Box::new(same_length_and_capacity::SameLengthAndCapacity)), Box::new(move |tcx| Box::new(duration_suboptimal_units::DurationSuboptimalUnits::new(tcx, conf))), diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs index 9aa4d2f0adc2c..bfd4d4bcd5644 100644 --- a/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs @@ -1,17 +1,19 @@ +use std::borrow::Cow; + use super::{EXPLICIT_COUNTER_LOOP, IncrementVisitor, InitializeVisitor, make_iterator_snippet}; -use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{get_enclosing_block, is_integer_const}; -use rustc_ast::Label; +use clippy_utils::sugg::{EMPTY, Sugg}; +use clippy_utils::{get_enclosing_block, is_integer_const, is_integer_literal_untyped}; +use rustc_ast::{Label, RangeLimits}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr}; use rustc_hir::{Expr, Pat}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty, UintTy}; -// To trigger the EXPLICIT_COUNTER_LOOP lint, a variable must be -// incremented exactly once in the loop body, and initialized to zero -// at the start of the loop. +// To trigger the EXPLICIT_COUNTER_LOOP lint, a variable must be incremented exactly once in the +// loop body. pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, @@ -31,34 +33,11 @@ pub(super) fn check<'tcx>( let mut initialize_visitor = InitializeVisitor::new(cx, expr, id); walk_block(&mut initialize_visitor, block); - if let Some((name, ty, initializer)) = initialize_visitor.get_result() - && is_integer_const(cx, initializer, 0) - { + if let Some((name, ty, initializer)) = initialize_visitor.get_result() { + let is_zero = is_integer_const(cx, initializer, 0); let mut applicability = Applicability::MaybeIncorrect; let span = expr.span.with_hi(arg.span.hi()); let loop_label = label.map_or(String::new(), |l| format!("{}: ", l.ident.name)); - let int_name = match ty.map(Ty::kind) { - // usize or inferred - Some(ty::Uint(UintTy::Usize)) | None => { - span_lint_and_sugg( - cx, - EXPLICIT_COUNTER_LOOP, - span, - format!("the variable `{name}` is used as a loop counter"), - "consider using", - format!( - "{loop_label}for ({name}, {}) in {}.enumerate()", - snippet_with_applicability(cx, pat.span, "item", &mut applicability), - make_iterator_snippet(cx, arg, &mut applicability), - ), - applicability, - ); - return; - }, - Some(ty::Int(int_ty)) => int_ty.name_str(), - Some(ty::Uint(uint_ty)) => uint_ty.name_str(), - _ => return, - }; span_lint_and_then( cx, @@ -66,20 +45,52 @@ pub(super) fn check<'tcx>( span, format!("the variable `{name}` is used as a loop counter"), |diag| { + let pat_snippet = snippet_with_applicability(cx, pat.span, "item", &mut applicability); + let iter_snippet = make_iterator_snippet(cx, arg, &mut applicability); + let int_name = match ty.map(Ty::kind) { + Some(ty::Uint(UintTy::Usize)) | None => { + if is_zero { + diag.span_suggestion( + span, + "consider using", + format!( + "{loop_label}for ({name}, {pat_snippet}) in {iter_snippet}.enumerate()", + ), + applicability, + ); + return; + } + None + }, + Some(ty::Int(int_ty)) => Some(int_ty.name_str()), + Some(ty::Uint(uint_ty)) => Some(uint_ty.name_str()), + _ => None, + } + .filter(|_| is_integer_literal_untyped(initializer)); + + let initializer = Sugg::hir_from_snippet(cx, initializer, |span| { + let snippet = snippet_with_applicability(cx, span, "..", &mut applicability); + if let Some(int_name) = int_name { + return Cow::Owned(format!("{snippet}_{int_name}")); + } + snippet + }); + diag.span_suggestion( span, "consider using", format!( - "{loop_label}for ({name}, {}) in (0_{int_name}..).zip({})", - snippet_with_applicability(cx, pat.span, "item", &mut applicability), - make_iterator_snippet(cx, arg, &mut applicability), + "{loop_label}for ({name}, {pat_snippet}) in ({}).zip({iter_snippet})", + initializer.range(&EMPTY, RangeLimits::HalfOpen) ), applicability, ); - diag.note(format!( - "`{name}` is of type `{int_name}`, making it ineligible for `Iterator::enumerate`" - )); + if is_zero && let Some(int_name) = int_name { + diag.note(format!( + "`{name}` is of type `{int_name}`, making it ineligible for `Iterator::enumerate`" + )); + } }, ); } diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs index 56d535c4f2625..2c37e2679d972 100644 --- a/src/tools/clippy/clippy_lints/src/loops/utils.rs +++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs @@ -57,19 +57,17 @@ impl<'tcx> Visitor<'tcx> for IncrementVisitor<'_, 'tcx> { } match parent.kind { - ExprKind::AssignOp(op, lhs, rhs) => { - if lhs.hir_id == expr.hir_id { - *state = if op.node == AssignOpKind::AddAssign - && is_integer_const(self.cx, rhs, 1) - && *state == IncrementVisitorVarState::Initial - && self.depth == 0 - { - IncrementVisitorVarState::IncrOnce - } else { - // Assigned some other value or assigned multiple times - IncrementVisitorVarState::DontWarn - }; - } + ExprKind::AssignOp(op, lhs, rhs) if lhs.hir_id == expr.hir_id => { + *state = if op.node == AssignOpKind::AddAssign + && is_integer_const(self.cx, rhs, 1) + && *state == IncrementVisitorVarState::Initial + && self.depth == 0 + { + IncrementVisitorVarState::IncrOnce + } else { + // Assigned some other value or assigned multiple times + IncrementVisitorVarState::DontWarn + }; }, ExprKind::Assign(lhs, _, _) if lhs.hir_id == expr.hir_id => { *state = IncrementVisitorVarState::DontWarn; diff --git a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs index db1ed269bb0ee..4d8f10506b595 100644 --- a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs +++ b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs @@ -243,8 +243,8 @@ impl<'tcx> LateLintPass<'tcx> for ExprMetavarsInUnsafe { // We want to lint unsafe blocks #0 and #1 let bad_unsafe_blocks = self .metavar_expns - .iter() - .filter_map(|(_, state)| match state { + .values() + .filter_map(|state| match state { MetavarState::ReferencedInUnsafe { unsafe_blocks } => Some(unsafe_blocks.as_slice()), MetavarState::ReferencedInSafe => None, }) diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs index cb3cc999c9361..8b92c3b8cbeb5 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -9,7 +9,9 @@ use rustc_ast::BindingMode; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::def::{CtorOf, DefKind, Res}; -use rustc_hir::{Arm, Expr, ExprKind, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath, Stmt, StmtKind}; +use rustc_hir::{ + Arm, BlockCheckMode, Expr, ExprKind, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath, Stmt, StmtKind, +}; use rustc_lint::{LateContext, LintContext}; use rustc_span::Span; use rustc_span::symbol::{Symbol, sym}; @@ -177,7 +179,10 @@ fn emit_manual_let_else( let (sn_expr, _) = snippet_with_context(cx, expr.span, span.ctxt(), "", &mut app); let (sn_else, else_is_mac_call) = snippet_with_context(cx, else_body.span, span.ctxt(), "", &mut app); - let else_bl = if matches!(else_body.kind, ExprKind::Block(..)) && !else_is_mac_call { + let else_bl = if let ExprKind::Block(block, None) = else_body.kind + && matches!(block.rules, BlockCheckMode::DefaultBlock) + && !else_is_mac_call + { sn_else.into_owned() } else { format!("{{ {sn_else} }}") diff --git a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs index 5cf90eecaa978..cb451d8c0da3f 100644 --- a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs +++ b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs @@ -59,12 +59,11 @@ impl LateLintPass<'_> for ManualOptionAsSlice { return; } match expr.kind { - ExprKind::Match(scrutinee, [arm1, arm2], _) => { + ExprKind::Match(scrutinee, [arm1, arm2], _) if is_none_pattern(cx, arm2.pat) && check_arms(cx, arm2, arm1) - || is_none_pattern(cx, arm1.pat) && check_arms(cx, arm1, arm2) - { - check_as_ref(cx, scrutinee, span, self.msrv); - } + || is_none_pattern(cx, arm1.pat) && check_arms(cx, arm1, arm2) => + { + check_as_ref(cx, scrutinee, span, self.msrv); }, ExprKind::If(cond, then, Some(other)) => { if let ExprKind::Let(let_expr) = cond.kind @@ -75,34 +74,24 @@ impl LateLintPass<'_> for ManualOptionAsSlice { check_as_ref(cx, let_expr.init, span, self.msrv); } }, - ExprKind::MethodCall(seg, callee, [], _) => { - if seg.ident.name == sym::unwrap_or_default { - check_map(cx, callee, span, self.msrv); - } + ExprKind::MethodCall(seg, callee, [], _) if seg.ident.name == sym::unwrap_or_default => { + check_map(cx, callee, span, self.msrv); }, ExprKind::MethodCall(seg, callee, [or], _) => match seg.ident.name { - sym::unwrap_or => { - if is_empty_slice(cx, or) { - check_map(cx, callee, span, self.msrv); - } + sym::unwrap_or if is_empty_slice(cx, or) => { + check_map(cx, callee, span, self.msrv); }, - sym::unwrap_or_else => { - if returns_empty_slice(cx, or) { - check_map(cx, callee, span, self.msrv); - } + sym::unwrap_or_else if returns_empty_slice(cx, or) => { + check_map(cx, callee, span, self.msrv); }, _ => {}, }, ExprKind::MethodCall(seg, callee, [or_else, map], _) => match seg.ident.name { - sym::map_or => { - if is_empty_slice(cx, or_else) && is_slice_from_ref(cx, map) { - check_as_ref(cx, callee, span, self.msrv); - } + sym::map_or if is_empty_slice(cx, or_else) && is_slice_from_ref(cx, map) => { + check_as_ref(cx, callee, span, self.msrv); }, - sym::map_or_else => { - if returns_empty_slice(cx, or_else) && is_slice_from_ref(cx, map) { - check_as_ref(cx, callee, span, self.msrv); - } + sym::map_or_else if returns_empty_slice(cx, or_else) && is_slice_from_ref(cx, map) => { + check_as_ref(cx, callee, span, self.msrv); }, _ => {}, }, diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index 8be53dbe4712a..a3f6ea2d88867 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -242,13 +242,13 @@ fn find_stripping<'tcx>( && self.cx.qpath_res(path, ex.hir_id) == self.target { match (self.strip_kind, start, end) { - (StripKind::Prefix, Some(start), None) => { - if eq_pattern_length(self.cx, self.pattern, start, self.ctxt) { - self.results.push(ex); - return; - } + (StripKind::Prefix, Some(start), None) + if eq_pattern_length(self.cx, self.pattern, start, self.ctxt) => + { + self.results.push(ex); + return; }, - (StripKind::Suffix, None, Some(end)) => { + (StripKind::Suffix, None, Some(end)) if let ExprKind::Binary( Spanned { node: BinOpKind::Sub, .. @@ -259,11 +259,10 @@ fn find_stripping<'tcx>( && let Some(left_arg) = len_arg(self.cx, left) && let ExprKind::Path(left_path) = &left_arg.kind && self.cx.qpath_res(left_path, left_arg.hir_id) == self.target - && eq_pattern_length(self.cx, self.pattern, right, self.ctxt) - { - self.results.push(ex); - return; - } + && eq_pattern_length(self.cx, self.pattern, right, self.ctxt) => + { + self.results.push(ex); + return; }, _ => {}, } diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs index b07d4fe81f8a9..6a02bb38d17b5 100644 --- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs +++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs @@ -193,8 +193,10 @@ fn let_binding_name(cx: &LateContext<'_>, var_arg: &hir::Expr<'_>) -> String { } #[must_use] -fn suggestion_msg(function_type: &str, map_type: &str) -> String { - format!("called `map(f)` on an `{map_type}` value where `f` is a {function_type} that returns the unit type `()`") +fn suggestion_msg(function_type: &str, article: &str, map_type: &str) -> String { + format!( + "called `map(f)` on {article} `{map_type}` value where `f` is a {function_type} that returns the unit type `()`" + ) } fn lint_map_unit_fn( @@ -205,10 +207,10 @@ fn lint_map_unit_fn( ) { let var_arg = &map_args.0; - let (map_type, variant, lint) = if cx.typeck_results().expr_ty(var_arg).is_diag_item(cx, sym::Option) { - ("Option", "Some", OPTION_MAP_UNIT_FN) + let (article, map_type, variant, lint) = if cx.typeck_results().expr_ty(var_arg).is_diag_item(cx, sym::Option) { + ("an", "Option", "Some", OPTION_MAP_UNIT_FN) } else if cx.typeck_results().expr_ty(var_arg).is_diag_item(cx, sym::Result) { - ("Result", "Ok", RESULT_MAP_UNIT_FN) + ("a", "Result", "Ok", RESULT_MAP_UNIT_FN) } else { return; }; @@ -219,7 +221,7 @@ fn lint_map_unit_fn( if is_unit_function(cx, fn_arg) { let mut applicability = Applicability::MachineApplicable; - let msg = suggestion_msg("function", map_type); + let msg = suggestion_msg("function", article, map_type); let suggestion = format!( "if let {0}({binding}) = {1} {{ {2}({binding}) }}", variant, @@ -232,7 +234,7 @@ fn lint_map_unit_fn( diag.span_suggestion_verbose(stmt.span, SUGG_MSG, suggestion, applicability); }); } else if let Some((binding, closure_expr)) = unit_closure(cx, fn_arg) { - let msg = suggestion_msg("closure", map_type); + let msg = suggestion_msg("closure", article, map_type); span_lint_and_then(cx, lint, expr.span, msg, |diag| { if let Some((reduced_expr_span, is_unsafe)) = reduce_unit_expression(cx, closure_expr) { diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs index 79f737f07eb1e..c95a72da6e29d 100644 --- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs @@ -1,17 +1,19 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::higher::IfLetOrMatch; +use clippy_utils::higher::{If, IfLetOrMatch}; use clippy_utils::msrvs::Msrv; use clippy_utils::res::{MaybeDef, MaybeResPath}; -use clippy_utils::source::snippet; +use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet}; use clippy_utils::visitors::is_local_used; use clippy_utils::{SpanlessEq, get_ref_operators, is_unit_expr, peel_blocks_with_stmt, peel_ref_operators}; use rustc_ast::BorrowKind; -use rustc_errors::MultiSpan; +use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::LangItem::OptionNone; use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatExpr, PatExprKind, PatKind}; use rustc_lint::LateContext; -use rustc_span::Span; use rustc_span::symbol::Ident; +use rustc_span::{BytePos, Span}; + +use crate::collapsible_if::{parens_around, peel_parens}; use super::{COLLAPSIBLE_MATCH, pat_contains_disallowed_or}; @@ -34,7 +36,7 @@ pub(super) fn check_if_let<'tcx>( check_arm(cx, false, pat, let_expr, body, None, else_expr, msrv); } -#[expect(clippy::too_many_arguments)] +#[expect(clippy::too_many_arguments, clippy::too_many_lines)] fn check_arm<'tcx>( cx: &LateContext<'tcx>, outer_is_match: bool, @@ -119,6 +121,70 @@ fn check_arm<'tcx>( "the outer pattern can be modified to include the inner pattern", ); }); + } else if outer_is_match // Leave if-let to the `collapsible_if` lint + && let Some(inner) = If::hir(inner_expr) + && outer_pat.span.eq_ctxt(inner.cond.span) + && match (outer_else_body, inner.r#else) { + (None, None) => true, + (None, Some(e)) | (Some(e), None) => is_unit_expr(e), + (Some(a), Some(b)) => SpanlessEq::new(cx).eq_expr(a, b), + } + { + span_lint_hir_and_then( + cx, + COLLAPSIBLE_MATCH, + inner_expr.hir_id, + inner_expr.span, + "this `if` can be collapsed into the outer `match`", + |diag| { + let outer_then_open_bracket = outer_then_body + .span + .split_at(1) + .0 + .with_leading_whitespace(cx) + .into_span(); + let outer_then_closing_bracket = { + let end = outer_then_body.span.shrink_to_hi(); + end.with_lo(end.lo() - BytePos(1)) + .with_leading_whitespace(cx) + .into_span() + }; + let outer_arrow_end = if let Some(outer_guard) = outer_guard { + outer_guard.span.shrink_to_hi() + } else { + outer_pat.span.shrink_to_hi() + }; + let (paren_start, inner_if_span, paren_end) = peel_parens(cx.tcx.sess.source_map(), inner_expr.span); + let inner_if = inner_if_span.split_at(2).0; + let mut sugg = vec![ + (inner.then.span.shrink_to_lo(), "=> ".to_string()), + (outer_arrow_end.to(outer_then_open_bracket), String::new()), + (outer_then_closing_bracket, String::new()), + ]; + + if let Some(outer_guard) = outer_guard { + sugg.extend(parens_around(outer_guard)); + sugg.push((inner_if, "&&".to_string())); + } + + if !paren_start.is_empty() { + sugg.push((paren_start, String::new())); + } + + if !paren_end.is_empty() { + sugg.push((paren_end, String::new())); + } + + sugg.extend(parens_around(inner.cond)); + + if let Some(else_inner) = inner.r#else { + let else_inner_span = inner.then.span.shrink_to_hi().to(else_inner.span); + sugg.push((else_inner_span, String::new())); + } + + diag.multipart_suggestion("collapse nested if block", sugg, Applicability::MachineApplicable); + }, + ); } } diff --git a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs index e40e21c490f3c..3c0fad01835f6 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs @@ -386,10 +386,8 @@ fn sugg_with_curlies<'a>( | Node::Expr(Expr { kind: ExprKind::Block(..) | ExprKind::ConstBlock(..), .. - }) => { - if needs_var_binding && is_var_binding_used_later { - add_curlies(); - } + }) if needs_var_binding && is_var_binding_used_later => { + add_curlies(); }, Node::Expr(..) | Node::AnonConst(..) diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs index 238e1fe988b39..de32b0476d205 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_with_context; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::peel_and_count_ty_refs; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -9,9 +10,10 @@ use rustc_span::symbol::sym; use super::CLONE_ON_REF_PTR; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>) { - let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); + let receiver_ty = cx.typeck_results().expr_ty(receiver); + let (receiver_ty_peeled, n_refs, _) = peel_and_count_ty_refs(receiver_ty); - if let ty::Adt(adt, subst) = obj_ty.kind() + if let ty::Adt(adt, subst) = receiver_ty_peeled.kind() && let Some(name) = cx.tcx.get_diagnostic_name(adt.did()) { let caller_type = match name { @@ -29,20 +31,26 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir:: |diag| { // Sometimes unnecessary ::<_> after Rc/Arc/Weak let mut app = Applicability::Unspecified; - let snippet = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut app).0; + let mut sugg = Sugg::hir_with_context(cx, receiver, expr.span.ctxt(), "..", &mut app); + if n_refs == 0 { + sugg = sugg.addr(); + } + // References on argument position don't need to preserve parentheses + // even if they were present in the original expression. + sugg = sugg.strip_paren(); let generic = subst.type_at(0); if generic.is_suggestable(cx.tcx, true) { diag.span_suggestion( expr.span, "try", - format!("{caller_type}::<{generic}>::clone(&{snippet})"), + format!("{caller_type}::<{generic}>::clone({sugg})"), app, ); } else { diag.span_suggestion( expr.span, "try", - format!("{caller_type}::::clone(&{snippet})"), + format!("{caller_type}::::clone({sugg})"), Applicability::HasPlaceholders, ); } diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs index 366bfaed73d48..79034fa23300a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs @@ -21,6 +21,7 @@ pub(super) fn check<'tcx>( recv: &'tcx Expr<'tcx>, // hashmap m_arg: &'tcx Expr<'tcx>, // |(_, v)| v msrv: Msrv, + method_name: Symbol, ) { if map_type == sym::into_iter && !msrv.meets(cx, msrvs::INTO_KEYS) { return; @@ -67,7 +68,7 @@ pub(super) fn check<'tcx>( format!("iterating on a map's {replacement_kind}s"), "try", format!( - "{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{}{bound_ident}| {body_snippet})", + "{recv_snippet}.{into_prefix}{replacement_kind}s().{method_name}(|{}{bound_ident}| {body_snippet})", annotation.prefix_str(), ), applicability, diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs index e3bcca64e9235..241791e57c8e6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -1,13 +1,15 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_copy}; +use clippy_utils::visitors::for_each_expr_without_closures; +use core::ops::ControlFlow; use rustc_ast::BindingMode; use rustc_errors::Applicability; -use rustc_hir::{Body, Expr, ExprKind, HirId, HirIdSet, PatKind}; +use rustc_hir::{Body, CaptureBy, Closure, Expr, ExprKind, HirId, HirIdSet, Param, PatKind}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use rustc_lint::LateContext; use rustc_middle::mir::{FakeReadCause, Mutability}; -use rustc_middle::ty::{self, BorrowKind}; +use rustc_middle::ty::{self, BorrowKind, UpvarCapture}; use rustc_span::{Symbol, sym}; use super::{ITER_OVEREAGER_CLONED, REDUNDANT_ITER_CLONED}; @@ -64,6 +66,11 @@ pub(super) fn check<'tcx>( let body @ Body { params: [p], .. } = cx.tcx.hir_body(closure.body) else { return; }; + + if param_captured_by_move_block(cx, body.value, p) { + return; + } + let mut delegate = MoveDelegate { used_move: HirIdSet::default(), }; @@ -140,6 +147,34 @@ struct MoveDelegate { used_move: HirIdSet, } +/// Checks if the expression contains a closure or coroutine with `move` capture semantics that +/// captures the given parameter. +fn param_captured_by_move_block(cx: &LateContext<'_>, expr: &Expr<'_>, param: &Param<'_>) -> bool { + let mut param_hir_ids = HirIdSet::default(); + param.pat.walk(|pat| { + param_hir_ids.insert(pat.hir_id); + true + }); + + for_each_expr_without_closures(expr, |e| { + if let ExprKind::Closure(Closure { + capture_clause: CaptureBy::Value { .. }, + def_id, + .. + }) = e.kind + && cx.tcx.closure_captures(*def_id).iter().any(|capture| { + matches!(capture.info.capture_kind, UpvarCapture::ByValue) + && matches!(capture.place.base, PlaceBase::Upvar(upvar) if param_hir_ids.contains(&upvar.var_path.hir_id)) + }) + { + return ControlFlow::Break(()); + } + + ControlFlow::Continue(()) + }) + .is_some() +} + impl<'tcx> Delegate<'tcx> for MoveDelegate { fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, _: HirId) { if let PlaceBase::Local(l) = place_with_id.place.base { diff --git a/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs b/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs index c731c2fc94342..248c76181250b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs +++ b/src/tools/clippy/clippy_lints/src/methods/join_absolute_paths.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{expr_or_init, sym}; use clippy_utils::res::MaybeDef; use clippy_utils::source::snippet; -use rustc_ast::ast::LitKind; +use rustc_ast::ast::{LitKind, StrStyle}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; @@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx Expr<'tcx>, join_a let ty = cx.typeck_results().expr_ty(recv).peel_refs(); if matches!(ty.opt_diag_name(cx), Some(sym::Path | sym::PathBuf)) && let ExprKind::Lit(spanned) = expr_or_init(cx, join_arg).kind - && let LitKind::Str(symbol, _) = spanned.node + && let LitKind::Str(symbol, style) = spanned.node && let sym_str = symbol.as_str() && sym_str.starts_with(['/', '\\']) { @@ -28,8 +28,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx Expr<'tcx>, join_a let no_separator = if sym_str.starts_with('/') { arg_str.replacen('/', "", 1) - } else { + } else if let StrStyle::Raw(_) = style { arg_str.replacen('\\', "", 1) + } else { + arg_str.replacen("\\\\", "", 1) }; diag.note("joining a path starting with separator will replace the path instead") diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs b/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs index d877b0a622918..472d21977c7ab 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs @@ -290,3 +290,43 @@ pub(super) fn check_or<'tcx>( }, ); } + +pub(super) fn check_is_some_is_none<'tcx>( + cx: &LateContext<'tcx>, + call_span: Span, + recv: &'tcx Expr<'tcx>, + arg: &'tcx Expr<'tcx>, + is_some: bool, + msrv: Msrv, +) { + if cx + .typeck_results() + .expr_ty_adjusted(recv) + .peel_refs() + .is_diag_item(cx, sym::Option) + && (is_some || msrv.meets(cx, msrvs::IS_NONE_OR)) + && let Ok(map_func) = MapFunc::try_from(arg) + { + let method = if is_some { "is_some_and" } else { "is_none_or" }; + let lint_span = recv.span.to(call_span); + span_lint_and_then( + cx, + MANUAL_IS_VARIANT_AND, + lint_span, + format!("manual implementation of `Option::{method}`"), + |diag| { + let mut app = Applicability::MachineApplicable; + let (recv_snip, _) = snippet_with_context(cx, recv.span, lint_span.ctxt(), "_", &mut app); + let map_func_snip = map_func.sugg(cx, !is_some, &mut app); + + // We need to use `as_ref()` because `filter` takes a reference + diag.span_suggestion( + lint_span, + "use", + format!("{recv_snip}.as_ref().{method}({map_func_snip})"), + app, + ); + }, + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 264405e6c3fb8..74db7ae03ba0b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -4760,6 +4760,7 @@ pub struct Methods { allow_unwrap_in_consts: bool, allowed_dotfiles: FxHashSet<&'static str>, format_args: FormatArgsStorage, + allow_unwrap_types: Vec, } impl Methods { @@ -4776,6 +4777,7 @@ impl Methods { allow_unwrap_in_consts: conf.allow_unwrap_in_consts, allowed_dotfiles, format_args, + allow_unwrap_types: conf.allow_unwrap_types.clone(), } } } @@ -4974,6 +4976,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { self.allow_expect_in_tests, self.allow_unwrap_in_consts, self.allow_expect_in_consts, + &self.allow_unwrap_types, ); }, ExprKind::MethodCall(..) => { @@ -5165,6 +5168,7 @@ impl Methods { format_collect::check(cx, expr, m_arg, m_ident_span); }, Some((sym::take, take_self_arg, [take_arg], _, _)) => { + #[expect(clippy::collapsible_match)] if self.msrv.meets(cx, msrvs::STR_REPEAT) { manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg); } @@ -5275,6 +5279,9 @@ impl Methods { call_span, self.msrv, ); + if let Some((map_name @ (sym::iter | sym::into_iter), recv2, _, _, _)) = method_call(recv) { + iter_kv_map::check(cx, map_name, expr, recv2, arg, self.msrv, sym::filter_map); + } }, (sym::find_map, [arg]) => { unnecessary_filter_map::check(cx, expr, arg, call_span, unnecessary_filter_map::Kind::FindMap); @@ -5285,6 +5292,9 @@ impl Methods { lines_filter_map_ok::check_filter_or_flat_map( cx, expr, recv, "flat_map", arg, call_span, self.msrv, ); + if let Some((map_name @ (sym::iter | sym::into_iter), recv2, _, _, _)) = method_call(recv) { + iter_kv_map::check(cx, map_name, expr, recv2, arg, self.msrv, sym::flat_map); + } }, (sym::flatten, []) => { match method_call(recv) { @@ -5343,8 +5353,8 @@ impl Methods { }, (sym::is_file, []) => filetype_is_file::check(cx, expr, recv), (sym::is_digit, [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv), - (sym::is_none, []) => check_is_some_is_none(cx, expr, recv, call_span, false), - (sym::is_some, []) => check_is_some_is_none(cx, expr, recv, call_span, true), + (sym::is_none, []) => check_is_some_is_none(cx, expr, recv, call_span, false, self.msrv), + (sym::is_some, []) => check_is_some_is_none(cx, expr, recv, call_span, true, self.msrv), (sym::iter | sym::iter_mut | sym::into_iter, []) => { iter_on_single_or_empty_collections::check(cx, expr, name, recv); }, @@ -5383,7 +5393,7 @@ impl Methods { manual_is_variant_and::check_map(cx, expr); match method_call(recv) { Some((map_name @ (sym::iter | sym::into_iter), recv2, _, _, _)) => { - iter_kv_map::check(cx, map_name, expr, recv2, m_arg, self.msrv); + iter_kv_map::check(cx, map_name, expr, recv2, m_arg, self.msrv, sym::map); }, Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check( cx, @@ -5484,7 +5494,9 @@ impl Methods { (sym::open, [_]) => { open_options::check(cx, expr, recv); }, - (sym::or_else, [arg]) => { + (sym::or_else, [arg]) => + { + #[expect(clippy::collapsible_match)] if !bind_instead_of_map::check_or_else_err(cx, expr, recv, arg) { unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); } @@ -5589,7 +5601,9 @@ impl Methods { (sym::try_into, []) if cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::TryInto) => { unnecessary_fallible_conversions::check_method(cx, expr); }, - (sym::to_owned, []) => { + (sym::to_owned, []) => + { + #[expect(clippy::collapsible_match)] if !suspicious_to_owned::check(cx, expr, span) { implicit_clone::check(cx, name, expr, recv); } @@ -5716,6 +5730,7 @@ impl Methods { false, self.allow_expect_in_consts, self.allow_expect_in_tests, + &self.allow_unwrap_types, unwrap_expect_used::Variant::Expect, ); expect_fun_call::check(cx, &self.format_args, expr, method_span, recv, arg); @@ -5728,6 +5743,7 @@ impl Methods { true, self.allow_expect_in_consts, self.allow_expect_in_tests, + &self.allow_unwrap_types, unwrap_expect_used::Variant::Expect, ); }, @@ -5748,6 +5764,7 @@ impl Methods { false, self.allow_unwrap_in_consts, self.allow_unwrap_in_tests, + &self.allow_unwrap_types, unwrap_expect_used::Variant::Unwrap, ); }, @@ -5759,6 +5776,7 @@ impl Methods { true, self.allow_unwrap_in_consts, self.allow_unwrap_in_tests, + &self.allow_unwrap_types, unwrap_expect_used::Variant::Unwrap, ); }, @@ -5768,7 +5786,14 @@ impl Methods { } } -fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, call_span: Span, is_some: bool) { +fn check_is_some_is_none<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + recv: &'tcx Expr<'tcx>, + call_span: Span, + is_some: bool, + msrv: Msrv, +) { match method_call(recv) { Some((name @ (sym::find | sym::position | sym::rposition), f_recv, [arg], span, _)) => { search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span); @@ -5779,6 +5804,9 @@ fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, Some((sym::first, f_recv, [], _, _)) => { unnecessary_first_then_check::check(cx, call_span, recv, f_recv, is_some); }, + Some((sym::filter, f_recv, [arg], _, _)) => { + manual_is_variant_and::check_is_some_is_none(cx, call_span, f_recv, arg, is_some, msrv); + }, _ => {}, } } diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs index 832197d36cc65..94c61a74dac60 100644 --- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs @@ -84,10 +84,10 @@ pub(super) fn check<'tcx>( return ControlFlow::Break(()); } }, - hir::ExprKind::MethodCall(..) => { - if check_or_fn_call(cx, name, method_span, receiver, arg, Some(lambda), expr.span, None) { - return ControlFlow::Break(()); - } + hir::ExprKind::MethodCall(..) + if check_or_fn_call(cx, name, method_span, receiver, arg, Some(lambda), expr.span, None) => + { + return ControlFlow::Break(()); }, _ => {}, } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs index 72f1c42da2ee3..54f3fe4105198 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -131,17 +131,13 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc } (true, true) }, - hir::ExprKind::MethodCall(segment, recv, [arg], _) => { + hir::ExprKind::MethodCall(segment, recv, [arg], _) if segment.ident.name == sym::then_some && cx.typeck_results().expr_ty(recv).is_bool() - && arg.res_local_id() == Some(arg_id) - { - // bool.then_some(arg_id) - (false, true) - } else { - // bool.then_some(not arg_id) - (true, true) - } + && arg.res_local_id() == Some(arg_id) => + { + // bool.then_some(arg_id) + (false, true) }, hir::ExprKind::Block(block, _) => block .expr diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs index c3f031edff2e2..367d98ece1951 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs @@ -89,6 +89,28 @@ impl Replacement { } } +fn get_triggered_expr_span( + left_expr: &hir::Expr<'_>, + right_expr: &hir::Expr<'_>, + first_arg_id: hir::HirId, + second_arg_id: hir::HirId, + replacement: Replacement, +) -> Option { + if left_expr.res_local_id() == Some(first_arg_id) + && (replacement.has_args || right_expr.res_local_id() == Some(second_arg_id)) + { + right_expr.span.into() + } + // https://github.com/rust-lang/rust-clippy/issues/16581 + else if right_expr.res_local_id() == Some(first_arg_id) + && (replacement.has_args || left_expr.res_local_id() == Some(second_arg_id)) + { + left_expr.span.into() + } else { + None + } +} + fn check_fold_with_op( cx: &LateContext<'_>, expr: &hir::Expr<'_>, @@ -111,8 +133,13 @@ fn check_fold_with_op( && let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(param_a.pat).kind && let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(param_b.pat).kind - && left_expr.res_local_id() == Some(first_arg_id) - && (replacement.has_args || right_expr.res_local_id() == Some(second_arg_id)) + && let Some(triggered_expr_span) = get_triggered_expr_span( + left_expr, + right_expr, + first_arg_id, + second_arg_id, + replacement + ) { let span = fold_span.with_hi(expr.span.hi()); span_lint_and_then( @@ -125,7 +152,7 @@ fn check_fold_with_op( let turbofish = replacement.maybe_turbofish(cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs()); let (r_snippet, _) = - snippet_with_context(cx, right_expr.span, expr.span.ctxt(), "EXPR", &mut applicability); + snippet_with_context(cx, triggered_expr_span, expr.span.ctxt(), "EXPR", &mut applicability); let sugg = if replacement.has_args { format!( "{method}{turbofish}(|{second_arg_ident}| {r_snippet})", diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs index bf91a469e7f01..ea1dff6369400 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs @@ -88,7 +88,17 @@ fn detect_extrema<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option< match (cv.int_value(cx.tcx, ty)?, ty.kind()) { (FullInt::S(i), &ty::Int(ity)) if i == i128::MIN >> (128 - ity.bit_width()?) => Some(Extrema::Minimum), (FullInt::S(i), &ty::Int(ity)) if i == i128::MAX >> (128 - ity.bit_width()?) => Some(Extrema::Maximum), - (FullInt::U(i), &ty::Uint(uty)) if i == u128::MAX >> (128 - uty.bit_width()?) => Some(Extrema::Maximum), + (FullInt::U(i), &ty::Uint(uty)) + if { + let bits = match uty { + ty::UintTy::Usize => u32::try_from(cx.tcx.data_layout.pointer_size().bits()).ok()?, + _ => u32::try_from(uty.bit_width()?).ok()?, + }; + i == u128::MAX >> (128 - bits) + } => + { + Some(Extrema::Maximum) + }, (FullInt::U(0), &ty::Uint(_)) => Some(Extrema::Minimum), _ => None, } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 607aaef9627bd..af5498c353d43 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -482,15 +482,11 @@ fn get_input_traits_and_projections<'tcx>( let mut projection_predicates = Vec::new(); for predicate in cx.tcx.param_env(callee_def_id).caller_bounds() { match predicate.kind().skip_binder() { - ClauseKind::Trait(trait_predicate) => { - if trait_predicate.trait_ref.self_ty() == input { - trait_predicates.push(trait_predicate); - } + ClauseKind::Trait(trait_predicate) if trait_predicate.trait_ref.self_ty() == input => { + trait_predicates.push(trait_predicate); }, - ClauseKind::Projection(projection_predicate) => { - if projection_predicate.projection_term.self_ty() == input { - projection_predicates.push(projection_predicate); - } + ClauseKind::Projection(projection_predicate) if projection_predicate.projection_term.self_ty() == input => { + projection_predicates.push(projection_predicate); }, _ => {}, } @@ -702,8 +698,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx sym::to_vec => cx .tcx .impl_of_assoc(method_def_id) - .filter(|&impl_did| cx.tcx.type_of(impl_did).instantiate_identity().is_slice()) - .is_some(), + .is_some_and(|impl_did| cx.tcx.type_of(impl_did).instantiate_identity().is_slice()), _ => false, } && let original_arg_ty = cx.typeck_results().node_type(caller.hir_id).peel_refs() diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs index 4effab3a5e63c..6d8777cbc23f8 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs @@ -36,6 +36,7 @@ impl Variant { /// Lint usage of `unwrap` or `unwrap_err` for `Result` and `unwrap()` for `Option` (and their /// `expect` counterparts). +#[allow(clippy::too_many_arguments)] pub(super) fn check( cx: &LateContext<'_>, expr: &Expr<'_>, @@ -43,6 +44,7 @@ pub(super) fn check( is_err: bool, allow_unwrap_in_consts: bool, allow_unwrap_in_tests: bool, + allow_unwrap_types: &[String], variant: Variant, ) { let ty = cx.typeck_results().expr_ty(recv).peel_refs(); @@ -64,6 +66,54 @@ pub(super) fn check( let method_suffix = if is_err { "_err" } else { "" }; + let ty_name = ty.to_string(); + if allow_unwrap_types + .iter() + .any(|allowed_type| ty_name.starts_with(allowed_type) || ty_name == *allowed_type) + { + return; + } + + for s in allow_unwrap_types { + let def_ids = clippy_utils::paths::lookup_path_str(cx.tcx, clippy_utils::paths::PathNS::Type, s); + for def_id in def_ids { + if let ty::Adt(adt, _) = ty.kind() + && adt.did() == def_id + { + return; + } + if cx.tcx.def_kind(def_id) == DefKind::TyAlias { + let alias_ty = cx.tcx.type_of(def_id).instantiate_identity(); + if let (ty::Adt(adt, substs), ty::Adt(alias_adt, alias_substs)) = (ty.kind(), alias_ty.kind()) + && adt.did() == alias_adt.did() + { + let mut all_match = true; + for (arg, alias_arg) in substs.iter().zip(alias_substs.iter()) { + if let (Some(arg_ty), Some(alias_arg_ty)) = (arg.as_type(), alias_arg.as_type()) { + if matches!(alias_arg_ty.kind(), ty::Param(_)) { + continue; + } + if let (ty::Adt(arg_adt, _), ty::Adt(alias_arg_adt, _)) = + (arg_ty.peel_refs().kind(), alias_arg_ty.peel_refs().kind()) + { + if arg_adt.did() != alias_arg_adt.did() { + all_match = false; + break; + } + } else if arg_ty != alias_arg_ty { + all_match = false; + break; + } + } + } + if all_match { + return; + } + } + } + } + } + if allow_unwrap_in_tests && is_in_test(cx.tcx, expr.hir_id) { return; } @@ -99,6 +149,7 @@ pub(super) fn check_call( allow_unwrap_in_tests: bool, allow_expect_in_consts: bool, allow_expect_in_tests: bool, + allow_unwrap_types: &[String], ) { let Some(recv) = args.first() else { return; @@ -116,6 +167,7 @@ pub(super) fn check_call( false, allow_unwrap_in_consts, allow_unwrap_in_tests, + allow_unwrap_types, Variant::Unwrap, ); }, @@ -127,6 +179,7 @@ pub(super) fn check_call( false, allow_expect_in_consts, allow_expect_in_tests, + allow_unwrap_types, Variant::Expect, ); }, @@ -138,6 +191,7 @@ pub(super) fn check_call( true, allow_unwrap_in_consts, allow_unwrap_in_tests, + allow_unwrap_types, Variant::Unwrap, ); }, @@ -149,6 +203,7 @@ pub(super) fn check_call( true, allow_expect_in_consts, allow_expect_in_tests, + allow_unwrap_types, Variant::Expect, ); }, diff --git a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs index 86348f04600b8..dcb185b51a096 100644 --- a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs +++ b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_test; -use clippy_utils::macros::{PanicExpn, find_assert_args, find_assert_eq_args, root_macro_call_first_node}; +use clippy_utils::macros::{find_assert_args, find_assert_eq_args, root_macro_call_first_node}; use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingAssertMessage { panic_expn }; - if let PanicExpn::Empty = panic_expn { + if panic_expn.is_default_message() { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] span_lint_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs index ddd4271960e13..53f97abe0b449 100644 --- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs @@ -154,18 +154,14 @@ impl<'tcx> Visitor<'tcx> for DivergenceVisitor<'_, 'tcx> { match e.kind { // fix #10776 ExprKind::Block(block, ..) => match (block.stmts, block.expr) { - (stmts, Some(e)) => { - if stmts.iter().all(|stmt| !stmt_might_diverge(stmt)) { - self.visit_expr(e); - } + (stmts, Some(e)) if stmts.iter().all(|stmt| !stmt_might_diverge(stmt)) => { + self.visit_expr(e); }, - ([first @ .., stmt], None) => { - if first.iter().all(|stmt| !stmt_might_diverge(stmt)) { - match stmt.kind { - StmtKind::Expr(e) | StmtKind::Semi(e) => self.visit_expr(e), - _ => {}, - } - } + ([first @ .., stmt], None) + if first.iter().all(|stmt| !stmt_might_diverge(stmt)) + && let StmtKind::Expr(e) | StmtKind::Semi(e) = stmt.kind => + { + self.visit_expr(e); }, _ => {}, }, diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs index 42dc9f2f1fa83..ebf7ccfd5ba7c 100644 --- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -165,10 +165,8 @@ impl<'tcx> Visitor<'tcx> for UnsafeExprCollector<'tcx> { return self.visit_expr(inner); }, - ExprKind::Field(e, _) => { - if self.typeck_results.expr_ty(e).is_union() { - self.insert_span(expr.span, "union field access occurs here"); - } + ExprKind::Field(e, _) if self.typeck_results.expr_ty(e).is_union() => { + self.insert_span(expr.span, "union field access occurs here"); }, ExprKind::Path(QPath::Resolved( diff --git a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs index 3b271ca0dc147..a18817ac716b8 100644 --- a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs +++ b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node}; +use clippy_utils::macros::{MacroCall, find_assert_args, find_assert_eq_args, root_macro_call_first_node}; use clippy_utils::sym; use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability}; @@ -43,33 +43,39 @@ impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall { let Some(macro_call) = root_macro_call_first_node(cx, e) else { return; }; - if !matches!( - cx.tcx.get_diagnostic_name(macro_call.def_id), - Some(sym::debug_assert_macro | sym::debug_assert_eq_macro | sym::debug_assert_ne_macro) - ) { - return; - } - let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn) else { - return; - }; - for arg in [lhs, rhs] { - let mut visitor = MutArgVisitor::new(cx); - visitor.visit_expr(arg); - if let Some(span) = visitor.expr_span() { - span_lint( - cx, - DEBUG_ASSERT_WITH_MUT_CALL, - span, - format!( - "do not call a function with mutable arguments inside of `{}!`", - cx.tcx.item_name(macro_call.def_id) - ), - ); - } + match cx.tcx.get_diagnostic_name(macro_call.def_id) { + Some(sym::debug_assert_macro) => { + if let Some((arg, _)) = find_assert_args(cx, e, macro_call.expn) { + check_arg(cx, arg, ¯o_call); + } + }, + Some(sym::debug_assert_ne_macro | sym::debug_assert_eq_macro) => { + if let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn) { + check_arg(cx, lhs, ¯o_call); + check_arg(cx, rhs, ¯o_call); + } + }, + _ => {}, } } } +fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>, macro_call: &MacroCall) { + let mut visitor = MutArgVisitor::new(cx); + visitor.visit_expr(arg); + if let Some(span) = visitor.expr_span() { + span_lint( + cx, + DEBUG_ASSERT_WITH_MUT_CALL, + span, + format!( + "do not call a function with mutable arguments inside of `{}!`", + cx.tcx.item_name(macro_call.def_id) + ), + ); + } +} + struct MutArgVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, expr_span: Option, diff --git a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs index 4bcd26c74f57f..e7ae54e0d0e16 100644 --- a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs +++ b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_from_proc_macro; use rustc_errors::Applicability; use rustc_hir::def_id::{DefId, DefIdMap}; use rustc_hir::{BoundPolarity, GenericBound, Generics, PolyTraitRef, TraitBoundModifiers, WherePredicateKind}; @@ -34,6 +35,7 @@ declare_clippy_lint! { declare_lint_pass!(NeedlessMaybeSized => [NEEDLESS_MAYBE_SIZED]); #[expect(clippy::struct_field_names)] +#[derive(Debug)] struct Bound<'tcx> { /// The [`DefId`] of the type parameter the bound refers to param: DefId, @@ -127,6 +129,7 @@ impl LateLintPass<'_> for NeedlessMaybeSized { if bound.trait_bound.modifiers == TraitBoundModifiers::NONE && let Some(sized_bound) = maybe_sized_params.get(&bound.param) && let Some(path) = path_to_sized_bound(cx, bound.trait_bound) + && !is_from_proc_macro(cx, bound.trait_bound) { span_lint_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs index fd5562f310e48..3c4dfade34399 100644 --- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -205,17 +205,13 @@ fn ty_allowed_with_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t .iter() .all(|ty| ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait)), ty::Array(ty, _) | ty::Slice(ty) => ty_allowed_with_raw_pointer_heuristic(cx, *ty, send_trait), - ty::Adt(_, args) => { - if contains_pointer_like(cx, ty) { - // descends only if ADT contains any raw pointers - args.iter().all(|generic_arg| match generic_arg.kind() { - GenericArgKind::Type(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait), - // Lifetimes and const generics are not solid part of ADT and ignored - GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => true, - }) - } else { - false - } + ty::Adt(_, args) if contains_pointer_like(cx, ty) => { + // descends only if ADT contains any raw pointers + args.iter().all(|generic_arg| match generic_arg.kind() { + GenericArgKind::Type(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait), + // Lifetimes and const generics are not solid part of ADT and ignored + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => true, + }) }, // Raw pointers are `!Send` but allowed by the heuristic ty::RawPtr(_, _) => true, @@ -231,10 +227,8 @@ fn contains_pointer_like<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> b ty::RawPtr(_, _) => { return true; }, - ty::Adt(adt_def, _) => { - if cx.tcx.is_diagnostic_item(sym::NonNull, adt_def.did()) { - return true; - } + ty::Adt(adt_def, _) if cx.tcx.is_diagnostic_item(sym::NonNull, adt_def.did()) => { + return true; }, _ => (), } diff --git a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs index d6af0234f010b..7f6dea573de83 100644 --- a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs +++ b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs @@ -71,15 +71,13 @@ fn check_bit_mask( span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero"); } }, - BinOpKind::BitOr => { - if mask_value | cmp_value != cmp_value { - span_lint( - cx, - BAD_BIT_MASK, - span, - format!("incompatible bit mask: `_ | {mask_value}` can never be equal to `{cmp_value}`"), - ); - } + BinOpKind::BitOr if mask_value | cmp_value != cmp_value => { + span_lint( + cx, + BAD_BIT_MASK, + span, + format!("incompatible bit mask: `_ | {mask_value}` can never be equal to `{cmp_value}`"), + ); }, _ => (), }, diff --git a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs index 92515bd3fb804..ce50e6e35dcc5 100644 --- a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs +++ b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs @@ -52,11 +52,9 @@ pub(crate) fn check<'tcx>( span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value); } }, - BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => { - if is_redundant_op(cx, right, 0, ctxt) { - let paren = needs_parenthesis(cx, expr, left); - span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value); - } + BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub if is_redundant_op(cx, right, 0, ctxt) => { + let paren = needs_parenthesis(cx, expr, left); + span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value); }, BinOpKind::Mul => { if is_redundant_op(cx, left, 1, ctxt) { @@ -67,11 +65,9 @@ pub(crate) fn check<'tcx>( span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value); } }, - BinOpKind::Div => { - if is_redundant_op(cx, right, 1, ctxt) { - let paren = needs_parenthesis(cx, expr, left); - span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value); - } + BinOpKind::Div if is_redundant_op(cx, right, 1, ctxt) => { + let paren = needs_parenthesis(cx, expr, left); + span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value); }, BinOpKind::BitAnd => { if is_redundant_op(cx, left, -1, ctxt) { diff --git a/src/tools/clippy/clippy_lints/src/operators/manual_div_ceil.rs b/src/tools/clippy/clippy_lints/src/operators/manual_div_ceil.rs index 5ed923d719bc8..6751532ecbc78 100644 --- a/src/tools/clippy/clippy_lints/src/operators/manual_div_ceil.rs +++ b/src/tools/clippy/clippy_lints/src/operators/manual_div_ceil.rs @@ -73,14 +73,13 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, op: BinOpKind, lhs: & build_suggestion(cx, expr, inner_lhs, rhs, &mut applicability); } }, - ExprKind::MethodCall(method, receiver, [next_multiple_of_arg], _) => { - // x.next_multiple_of(Y) / Y + ExprKind::MethodCall(method, receiver, [next_multiple_of_arg], _) if method.ident.name == sym::next_multiple_of && check_int_ty(cx.typeck_results().expr_ty(receiver)) - && check_eq_expr(cx, next_multiple_of_arg, rhs) - { - build_suggestion(cx, expr, receiver, rhs, &mut applicability); - } + && check_eq_expr(cx, next_multiple_of_arg, rhs) => + { + // x.next_multiple_of(Y) / Y + build_suggestion(cx, expr, receiver, rhs, &mut applicability); }, ExprKind::Call(callee, [receiver, next_multiple_of_arg]) => { // int_type::next_multiple_of(x, Y) / Y diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs index 383b135dfa506..5b00f1b0bd13f 100644 --- a/src/tools/clippy/clippy_lints/src/operators/mod.rs +++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs @@ -1064,7 +1064,9 @@ impl<'tcx> LateLintPass<'tcx> for Operators { assign_op_pattern::check(cx, e, lhs, rhs, self.msrv); self_assignment::check(cx, e, lhs, rhs); }, - ExprKind::Unary(op, arg) => { + ExprKind::Unary(op, arg) => + { + #[expect(clippy::collapsible_match)] if op == UnOp::Neg { self.arithmetic_context.check_negate(cx, e, arg); } diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index 5517b7f260eaa..719f364357d3d 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -490,8 +490,7 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: || is_early_return(sym::Result, cx, &if_block)) && if_else .map(|e| eq_expr_value(cx, let_expr, peel_blocks(e))) - .filter(|e| *e) - .is_none() + .is_none_or(|e| !e) { if !is_copy(cx, caller_ty) && let Some(hir_id) = let_expr.res_local_id() diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs index b4e1f70d1535b..da85125730a84 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs @@ -66,25 +66,19 @@ impl RedundantStaticLifetimes { // Match the 'static lifetime if let Some(lifetime) = *optional_lifetime { match borrow_type.ty.kind { - TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => { - if lifetime.ident.name == kw::StaticLifetime { - let snip = snippet(cx, borrow_type.ty.span, ""); - let sugg = format!("&{}{snip}", borrow_type.mutbl.prefix_str()); - span_lint_and_then( - cx, - REDUNDANT_STATIC_LIFETIMES, - lifetime.ident.span, - reason, - |diag| { - diag.span_suggestion( - ty.span, - "consider removing `'static`", - sugg, - Applicability::MachineApplicable, //snippet - ); - }, + TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) + if lifetime.ident.name == kw::StaticLifetime => + { + let snip = snippet(cx, borrow_type.ty.span, ""); + let sugg = format!("&{}{snip}", borrow_type.mutbl.prefix_str()); + span_lint_and_then(cx, REDUNDANT_STATIC_LIFETIMES, lifetime.ident.span, reason, |diag| { + diag.span_suggestion( + ty.span, + "consider removing `'static`", + sugg, + Applicability::MachineApplicable, //snippet ); - } + }); }, _ => {}, } diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs index 8c4a50041e67d..143be5137038e 100644 --- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs +++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs @@ -138,14 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { return; }, }, - sym::alloc => { - if cx.tcx.crate_name(def_id.krate) == sym::core { - (ALLOC_INSTEAD_OF_CORE, "alloc", "core") - } else { - self.lint_if_finish(cx, first_segment.ident.span, LintPoint::Conflict); - return; - } - }, + sym::alloc if cx.tcx.crate_name(def_id.krate) == sym::core => (ALLOC_INSTEAD_OF_CORE, "alloc", "core"), _ => { self.lint_if_finish(cx, first_segment.ident.span, LintPoint::Conflict); return; diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 509ad4e4fcb3b..9d3e4a6b1d929 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -155,36 +155,32 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd { }, left, _, - ) => { - if is_string(cx, left) { - if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) { - let parent = get_parent_expr(cx, e); - if let Some(p) = parent + ) if is_string(cx, left) => { + if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) { + let parent = get_parent_expr(cx, e); + if let Some(p) = parent && let ExprKind::Assign(target, _, _) = p.kind // avoid duplicate matches && SpanlessEq::new(cx).eq_expr(target, left) - { - return; - } + { + return; } - span_lint( - cx, - STRING_ADD, - e.span, - "you added something to a string. Consider using `String::push_str()` instead", - ); } + span_lint( + cx, + STRING_ADD, + e.span, + "you added something to a string. Consider using `String::push_str()` instead", + ); }, - ExprKind::Assign(target, src, _) => { - if is_string(cx, target) && is_add(cx, src, target) { - span_lint( - cx, - STRING_ADD_ASSIGN, - e.span, - "you assigned the result of adding something to this string. Consider using \ + ExprKind::Assign(target, src, _) if is_string(cx, target) && is_add(cx, src, target) => { + span_lint( + cx, + STRING_ADD_ASSIGN, + e.span, + "you assigned the result of adding something to this string. Consider using \ `String::push_str()` instead", - ); - } + ); }, ExprKind::Index(target, _idx, _) => { let e_ty = cx.typeck_results().expr_ty_adjusted(target).peel_refs(); @@ -417,6 +413,8 @@ impl<'tcx> LateLintPass<'tcx> for StrToString { && args.iter().any(|a| a.hir_id == expr.hir_id) && let Res::Def(DefKind::AssocFn, def_id) = expr.res(cx) && cx.tcx.is_diagnostic_item(sym::to_string_method, def_id) + && let Some(args) = cx.typeck_results().node_args_opt(expr.hir_id) + && args.type_at(0).is_str() { // Detected `ToString::to_string` passed as an argument (generic: any call or method call) span_lint_and_sugg( @@ -425,7 +423,7 @@ impl<'tcx> LateLintPass<'tcx> for StrToString { expr.span, "`ToString::to_string` used as `&str` to `String` converter", "try", - "ToOwned::to_owned".to_string(), + "str::to_owned".to_string(), Applicability::MachineApplicable, ); } diff --git a/src/tools/clippy/clippy_lints/src/time_subtraction.rs b/src/tools/clippy/clippy_lints/src/time_subtraction.rs index e7bf58078c3db..457a8f48f7e2b 100644 --- a/src/tools/clippy/clippy_lints/src/time_subtraction.rs +++ b/src/tools/clippy/clippy_lints/src/time_subtraction.rs @@ -1,14 +1,18 @@ +use std::time::Duration; + use clippy_config::Conf; -use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::consts::{ConstEvalCtxt, Constant}; +use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; use clippy_utils::sugg::Sugg; use clippy_utils::sym; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; +use rustc_span::SyntaxContext; declare_clippy_lint! { /// ### What it does @@ -111,6 +115,27 @@ impl LateLintPass<'_> for UncheckedTimeSubtraction { && !expr.span.from_expansion() && self.msrv.meets(cx, msrvs::TRY_FROM) { + let const_eval = ConstEvalCtxt::new(cx); + let ctxt = expr.span.ctxt(); + if let Some(lhs) = const_eval_duration(&const_eval, lhs, ctxt) + && let Some(rhs) = const_eval_duration(&const_eval, rhs, ctxt) + { + if lhs >= rhs { + // If the duration subtraction can be proven to not underflow, then we don't lint + return; + } + + span_lint_and_note( + cx, + UNCHECKED_TIME_SUBTRACTION, + expr.span, + "unchecked subtraction of two `Duration` that will underflow", + None, + "if this is intentional, consider allowing the lint", + ); + return; + } + print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); } } @@ -189,3 +214,44 @@ fn print_unchecked_duration_subtraction_sugg( }, ); } + +fn const_eval_duration(const_eval: &ConstEvalCtxt<'_>, expr: &Expr<'_>, ctxt: SyntaxContext) -> Option { + if let ExprKind::Call(func, args) = expr.kind + && let ExprKind::Path(QPath::TypeRelative(_, func_name)) = func.kind + { + macro_rules! try_parse_duration { + (($( $name:ident : $var:ident ( $ty:ty ) ),+ $(,)?) -> $ctor:ident ( $($args:tt)* )) => {{ + let [$( $name ),+] = args else { return None }; + $( + let Some(Constant::$var(v)) = const_eval.eval_local($name, ctxt) else { return None }; + let $name = <$ty>::try_from(v).ok()?; + )+ + Some(Duration::$ctor($($args)*)) + }}; + } + + return match func_name.ident.name { + sym::new => try_parse_duration! { (secs: Int(u64), nanos: Int(u32)) -> new(secs, nanos) }, + sym::from_nanos => try_parse_duration! { (nanos: Int(u64)) -> from_nanos(nanos) }, + sym::from_nanos_u128 => try_parse_duration! { (nanos: Int(u128)) -> from_nanos_u128(nanos) }, + sym::from_micros => try_parse_duration! { (micros: Int(u64)) -> from_micros(micros) }, + sym::from_millis => try_parse_duration! { (millis: Int(u64)) -> from_millis(millis) }, + sym::from_secs => try_parse_duration! { (secs: Int(u64)) -> from_secs(secs) }, + sym::from_secs_f32 => try_parse_duration! { (secs: F32(f32)) -> from_secs_f32(secs) }, + sym::from_secs_f64 => try_parse_duration! { (secs: F64(f64)) -> from_secs_f64(secs) }, + sym::from_mins => try_parse_duration! { (mins: Int(u64)) -> from_mins(mins) }, + sym::from_hours => { + try_parse_duration! { (hours: Int(u64)) -> from_hours(hours) } + }, + sym::from_days => { + try_parse_duration! { (days: Int(u64)) -> from_hours(days * 24) } + }, + sym::from_weeks => { + try_parse_duration! { (weeks: Int(u64)) -> from_hours(weeks * 24 * 7) } + }, + _ => None, + }; + } + + None +} diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index 4ce132e9e3abd..e287a3de86bd7 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -157,7 +157,9 @@ fn into_iter_deep_call<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) - impl<'tcx> LateLintPass<'tcx> for UselessConversion { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { if e.span.from_expansion() { - self.expn_depth += 1; + if e.span.desugaring_kind().is_none() { + self.expn_depth += 1; + } return; } @@ -437,7 +439,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if Some(&e.hir_id) == self.try_desugar_arm.last() { self.try_desugar_arm.pop(); } - if e.span.from_expansion() { + if e.span.from_expansion() && e.span.desugaring_kind().is_none() { self.expn_depth -= 1; } } diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md index 1b85dcfd848d5..87048ceff8914 100644 --- a/src/tools/clippy/clippy_utils/README.md +++ b/src/tools/clippy/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2026-02-11 +nightly-2026-02-19 ``` diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 239f721ae05be..67ae1dcef81be 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -820,8 +820,8 @@ pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool { matches!( (l, r), (Defaultness::Implicit, Defaultness::Implicit) - | (Defaultness::Default(_), Defaultness::Default(_)) - | (Defaultness::Final(_), Defaultness::Final(_)) + | (Defaultness::Default(_), Defaultness::Default(_)) + | (Defaultness::Final(_), Defaultness::Final(_)) ) } diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index def5d968b063f..1b2ba0fe182af 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -21,10 +21,10 @@ use rustc_ast::ast::{ use rustc_ast::token::CommentKind; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl, - ImplItem, ImplItemImplKind, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, - QPath, Safety, TraitImplHeader, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, - YieldSource, + Block, BlockCheckMode, Body, BoundConstness, BoundPolarity, Closure, Destination, Expr, ExprKind, FieldDef, + FnHeader, FnRetTy, HirId, Impl, ImplItem, ImplItemImplKind, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, + MatchSource, MutTy, Node, Path, PolyTraitRef, QPath, Safety, TraitBoundModifiers, TraitImplHeader, TraitItem, + TraitItemKind, TraitRef, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource, }; use rustc_lint::{EarlyContext, LateContext, LintContext}; use rustc_middle::ty::TyCtxt; @@ -541,6 +541,44 @@ fn ast_ty_search_pat(ty: &ast::Ty) -> (Pat, Pat) { } } +// NOTE: can't `impl WithSearchPat for TraitRef`, because `TraitRef` doesn't have a `span` field +// (nor a method) +fn trait_ref_search_pat(trait_ref: &TraitRef<'_>) -> (Pat, Pat) { + path_search_pat(trait_ref.path) +} + +fn poly_trait_ref_search_pat(poly_trait_ref: &PolyTraitRef<'_>) -> (Pat, Pat) { + // NOTE: unfortunately we can't use `bound_generic_params` to see whether the pattern starts with + // `for<..>`, because if it's empty, we could have either `for<>` (nothing bound), or + // no `for` at all + let PolyTraitRef { + modifiers: TraitBoundModifiers { constness, polarity }, + trait_ref, + .. + } = poly_trait_ref; + + let trait_ref_search_pat = trait_ref_search_pat(trait_ref); + + #[expect( + clippy::unnecessary_lazy_evaluations, + reason = "the closure in `or_else` has `match polarity`, which isn't free" + )] + let start = match constness { + BoundConstness::Never => None, + BoundConstness::Maybe(_) => Some(Pat::Str("[const]")), + BoundConstness::Always(_) => Some(Pat::Str("const")), + } + .or_else(|| match polarity { + BoundPolarity::Negative(_) => Some(Pat::Str("!")), + BoundPolarity::Maybe(_) => Some(Pat::Str("?")), + BoundPolarity::Positive => None, + }) + .unwrap_or(trait_ref_search_pat.0); + let end = trait_ref_search_pat.1; + + (start, end) +} + fn ident_search_pat(ident: Ident) -> (Pat, Pat) { (Pat::Sym(ident.name), Pat::Sym(ident.name)) } @@ -573,6 +611,7 @@ impl_with_search_pat!((_cx: LateContext<'tcx>, self: Ty<'_>) => ty_search_pat(se impl_with_search_pat!((_cx: LateContext<'tcx>, self: Ident) => ident_search_pat(*self)); impl_with_search_pat!((_cx: LateContext<'tcx>, self: Lit) => lit_search_pat(&self.node)); impl_with_search_pat!((_cx: LateContext<'tcx>, self: Path<'_>) => path_search_pat(self)); +impl_with_search_pat!((_cx: LateContext<'tcx>, self: PolyTraitRef<'_>) => poly_trait_ref_search_pat(self)); impl_with_search_pat!((_cx: EarlyContext<'tcx>, self: Attribute) => attr_search_pat(self)); impl_with_search_pat!((_cx: EarlyContext<'tcx>, self: ast::Ty) => ast_ty_search_pat(self)); diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index 4ba9af58f90a1..81b06ea0c539b 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -104,14 +104,7 @@ fn validate_diag(diag: &Diag<'_, impl EmissionGuarantee>) { /// ``` #[track_caller] pub fn span_lint(cx: &T, lint: &'static Lint, sp: impl Into, msg: impl Into) { - #[expect(clippy::disallowed_methods)] - cx.span_lint(lint, sp, |diag| { - diag.primary_message(msg); - docs_link(diag, lint); - - #[cfg(debug_assertions)] - validate_diag(diag); - }); + span_lint_and_then(cx, lint, sp, msg, |_| {}); } /// Same as [`span_lint`] but with an extra `help` message. @@ -157,18 +150,12 @@ pub fn span_lint_and_help( help_span: Option, help: impl Into, ) { - #[expect(clippy::disallowed_methods)] - cx.span_lint(lint, span, |diag| { - diag.primary_message(msg); + span_lint_and_then(cx, lint, span, msg, |diag| { if let Some(help_span) = help_span { diag.span_help(help_span, help.into()); } else { diag.help(help.into()); } - docs_link(diag, lint); - - #[cfg(debug_assertions)] - validate_diag(diag); }); } @@ -218,18 +205,12 @@ pub fn span_lint_and_note( note_span: Option, note: impl Into, ) { - #[expect(clippy::disallowed_methods)] - cx.span_lint(lint, span, |diag| { - diag.primary_message(msg); + span_lint_and_then(cx, lint, span, msg, |diag| { if let Some(note_span) = note_span { diag.span_note(note_span, note.into()); } else { diag.note(note.into()); } - docs_link(diag, lint); - - #[cfg(debug_assertions)] - validate_diag(diag); }); } @@ -296,14 +277,7 @@ where /// the `#[allow]` will work. #[track_caller] pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: impl Into) { - #[expect(clippy::disallowed_methods)] - cx.tcx.node_span_lint(lint, hir_id, sp, |diag| { - diag.primary_message(msg); - docs_link(diag, lint); - - #[cfg(debug_assertions)] - validate_diag(diag); - }); + span_lint_hir_and_then(cx, lint, hir_id, sp, msg, |_| {}); } /// Like [`span_lint_and_then`], but emits the lint at the node identified by the given `HirId`. @@ -383,7 +357,6 @@ pub fn span_lint_hir_and_then( /// | /// = note: `-D fold-any` implied by `-D warnings` /// ``` -#[cfg_attr(not(debug_assertions), expect(clippy::collapsible_span_lint_calls))] #[track_caller] pub fn span_lint_and_sugg( cx: &T, @@ -397,7 +370,9 @@ pub fn span_lint_and_sugg( span_lint_and_then(cx, lint, sp, msg.into(), |diag| { diag.span_suggestion(sp, help.into(), sugg, applicability); - #[cfg(debug_assertions)] - validate_diag(diag); + // This dummy construct is here to prevent the internal `clippy::collapsible_span_lint_calls` + // lint from triggering. We don't want to allow/expect it as internal lints might or might + // not be activated when linting, and we don't want an unknown lint warning either. + std::hint::black_box(()); }); } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index fdd270c2774af..f2f8cd583f31f 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1144,6 +1144,27 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio }) } +/// Returns the [`Closure`] enclosing `hir_id`, if any. +pub fn get_enclosing_closure<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Closure<'tcx>> { + cx.tcx.hir_parent_iter(hir_id).find_map(|(_, node)| { + if let Node::Expr(expr) = node + && let ExprKind::Closure(closure) = expr.kind + { + Some(closure) + } else { + None + } + }) +} + +/// Checks whether a local identified by `local_id` is captured as an upvar by the given `closure`. +pub fn is_upvar_in_closure(cx: &LateContext<'_>, closure: &Closure<'_>, local_id: HirId) -> bool { + cx.typeck_results() + .closure_min_captures + .get(&closure.def_id) + .is_some_and(|x| x.contains_key(&local_id)) +} + /// Gets the loop or closure enclosing the given expression, if any. pub fn get_enclosing_loop_or_multi_call_closure<'tcx>( cx: &LateContext<'tcx>, @@ -2341,12 +2362,11 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl FnOnce(& && let item = tcx.hir_item(id) && let ItemKind::Const(ident, _generics, ty, _body) = item.kind && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind - // We could also check for the type name `test::TestDescAndFn` - && let Res::Def(DefKind::Struct, _) = path.res + // We could also check for the type name `test::TestDescAndFn` + && let Res::Def(DefKind::Struct, _) = path.res + && find_attr!(tcx.hir_attrs(item.hir_id()), RustcTestMarker(..)) { - if find_attr!(tcx.hir_attrs(item.hir_id()), RustcTestMarker(..)) { - names.push(ident.name); - } + names.push(ident.name); } } names.sort_unstable(); @@ -3245,6 +3265,8 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St None } }))) + } else if go_up_by == 0 && path.is_empty() { + String::from("Self") } else { join_path_syms(repeat_n(kw::Super, go_up_by).chain(path)) } diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs index 3cfe648fdf322..ed5db32d11179 100644 --- a/src/tools/clippy/clippy_utils/src/macros.rs +++ b/src/tools/clippy/clippy_utils/src/macros.rs @@ -234,19 +234,30 @@ pub fn is_assert_macro(cx: &LateContext<'_>, def_id: DefId) -> bool { matches!(name, sym::assert_macro | sym::debug_assert_macro) } +/// A call to a function in [`std::rt`] or [`core::panicking`] that results in a panic, typically +/// part of a `panic!()` expansion (often wrapped in a block) but may be called directly by other +/// macros such as `assert`. #[derive(Debug)] -pub enum PanicExpn<'a> { - /// No arguments - `panic!()` - Empty, - /// A string literal or any `&str` - `panic!("message")` or `panic!(message)` - Str(&'a Expr<'a>), - /// A single argument that implements `Display` - `panic!("{}", object)` +pub enum PanicCall<'a> { + // The default message - `panic!()`, `assert!(true)`, etc. + DefaultMessage, + /// A string literal or any `&str` in edition 2015/2018 - `panic!("message")` or + /// `panic!(message)`. + /// + /// In edition 2021+ `panic!("message")` will be a [`PanicCall::Format`] and `panic!(message)` a + /// compile error. + Str2015(&'a Expr<'a>), + /// A single argument that implements `Display` - `panic!("{}", object)`. + /// + /// `panic!("{object}")` will still be a [`PanicCall::Format`]. Display(&'a Expr<'a>), - /// Anything else - `panic!("error {}: {}", a, b)` + /// Anything else - `panic!("error {}: {}", a, b)`, `panic!("on edition 2021+")`. + /// + /// See [`FormatArgsStorage::get`] to examine the contents of the formatting. Format(&'a Expr<'a>), } -impl<'a> PanicExpn<'a> { +impl<'a> PanicCall<'a> { pub fn parse(expr: &'a Expr<'a>) -> Option { let ExprKind::Call(callee, args) = &expr.kind else { return None; @@ -260,8 +271,13 @@ impl<'a> PanicExpn<'a> { return None; }; let result = match name { - sym::panic if arg.span.eq_ctxt(expr.span) => Self::Empty, - sym::panic | sym::panic_str => Self::Str(arg), + sym::panic | sym::begin_panic | sym::panic_str_2015 => { + if arg.span.eq_ctxt(expr.span) || arg.span.is_dummy() { + Self::DefaultMessage + } else { + Self::Str2015(arg) + } + }, sym::panic_display => { let ExprKind::AddrOf(_, _, e) = &arg.kind else { return None; @@ -281,13 +297,17 @@ impl<'a> PanicExpn<'a> { let msg_arg = &rest[2]; match msg_arg.kind { ExprKind::Call(_, [fmt_arg]) => Self::Format(fmt_arg), - _ => Self::Empty, + _ => Self::DefaultMessage, } }, _ => return None, }; Some(result) } + + pub fn is_default_message(&self) -> bool { + matches!(self, Self::DefaultMessage) + } } /// Finds the arguments of an `assert!` or `debug_assert!` macro call within the macro expansion @@ -295,18 +315,8 @@ pub fn find_assert_args<'a>( cx: &LateContext<'_>, expr: &'a Expr<'a>, expn: ExpnId, -) -> Option<(&'a Expr<'a>, PanicExpn<'a>)> { - find_assert_args_inner(cx, expr, expn).map(|([e], mut p)| { - // `assert!(..)` expands to `core::panicking::panic("assertion failed: ...")` (which we map to - // `PanicExpn::Str(..)`) and `assert!(.., "..")` expands to - // `core::panicking::panic_fmt(format_args!(".."))` (which we map to `PanicExpn::Format(..)`). - // So even we got `PanicExpn::Str(..)` that means there is no custom message provided - if let PanicExpn::Str(_) = p { - p = PanicExpn::Empty; - } - - (e, p) - }) +) -> Option<(&'a Expr<'a>, PanicCall<'a>)> { + find_assert_args_inner(cx, expr, expn).map(|([e], p)| (e, p)) } /// Finds the arguments of an `assert_eq!` or `debug_assert_eq!` macro call within the macro @@ -315,7 +325,7 @@ pub fn find_assert_eq_args<'a>( cx: &LateContext<'_>, expr: &'a Expr<'a>, expn: ExpnId, -) -> Option<(&'a Expr<'a>, &'a Expr<'a>, PanicExpn<'a>)> { +) -> Option<(&'a Expr<'a>, &'a Expr<'a>, PanicCall<'a>)> { find_assert_args_inner(cx, expr, expn).map(|([a, b], p)| (a, b, p)) } @@ -323,7 +333,7 @@ fn find_assert_args_inner<'a, const N: usize>( cx: &LateContext<'_>, expr: &'a Expr<'a>, expn: ExpnId, -) -> Option<([&'a Expr<'a>; N], PanicExpn<'a>)> { +) -> Option<([&'a Expr<'a>; N], PanicCall<'a>)> { let macro_id = expn.expn_data().macro_def_id?; let (expr, expn) = match cx.tcx.item_name(macro_id).as_str().strip_prefix("debug_") { None => (expr, expn), @@ -332,7 +342,7 @@ fn find_assert_args_inner<'a, const N: usize>( let mut args = ArrayVec::new(); let panic_expn = for_each_expr_without_closures(expr, |e| { if args.is_full() { - match PanicExpn::parse(e) { + match PanicCall::parse(e) { Some(expn) => ControlFlow::Break(expn), None => ControlFlow::Continue(Descend::Yes), } @@ -344,10 +354,7 @@ fn find_assert_args_inner<'a, const N: usize>( } }); let args = args.into_inner().ok()?; - // if no `panic!(..)` is found, use `PanicExpn::Empty` - // to indicate that the default assertion message is used - let panic_expn = panic_expn.unwrap_or(PanicExpn::Empty); - Some((args, panic_expn)) + Some((args, panic_expn?)) } fn find_assert_within_debug_assert<'a>( diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs index 18fab6035f284..5aa457b9d19c4 100644 --- a/src/tools/clippy/clippy_utils/src/msrvs.rs +++ b/src/tools/clippy/clippy_utils/src/msrvs.rs @@ -142,12 +142,10 @@ impl Msrv { match (self.0, cargo_msrv) { (None, Some(cargo_msrv)) => self.0 = Some(cargo_msrv), - (Some(clippy_msrv), Some(cargo_msrv)) => { - if clippy_msrv != cargo_msrv { - sess.dcx().warn(format!( - "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`" - )); - } + (Some(clippy_msrv), Some(cargo_msrv)) if clippy_msrv != cargo_msrv => { + sess.dcx().warn(format!( + "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`" + )); }, _ => {}, } diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index e6593aa8b5541..3bd98ef240382 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -26,6 +26,7 @@ pub enum PathNS { Type, Value, Macro, + Field, /// Resolves to the name in the first available namespace, e.g. for `std::vec` this would return /// either the macro or the module but **not** both @@ -41,6 +42,7 @@ impl PathNS { PathNS::Type => TypeNS, PathNS::Value => ValueNS, PathNS::Macro => MacroNS, + PathNS::Field => return false, PathNS::Arbitrary => return true, }; @@ -286,6 +288,20 @@ fn local_item_child_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, ns: PathNS, n &root_mod }, Node::Item(item) => &item.kind, + Node::Variant(variant) if ns == PathNS::Field => { + return if let rustc_hir::VariantData::Struct { fields, .. } = variant.data + && let Some(field_def_id) = fields.iter().find_map(|field| { + if field.ident.name == name { + Some(field.def_id.to_def_id()) + } else { + None + } + }) { + Some(field_def_id) + } else { + None + }; + }, _ => return None, }; @@ -299,6 +315,7 @@ fn local_item_child_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, ns: PathNS, n PathNS::Type => opt_def_id(path.res.type_ns), PathNS::Value => opt_def_id(path.res.value_ns), PathNS::Macro => opt_def_id(path.res.macro_ns), + PathNS::Field => None, PathNS::Arbitrary => unreachable!(), } } else { @@ -318,6 +335,24 @@ fn local_item_child_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, ns: PathNS, n .filter_by_name_unhygienic(name) .find(|assoc_item| ns.matches(Some(assoc_item.namespace()))) .map(|assoc_item| assoc_item.def_id), + ItemKind::Struct(_, _, rustc_hir::VariantData::Struct { fields, .. }) if ns == PathNS::Field => { + fields.iter().find_map(|field| { + if field.ident.name == name { + Some(field.def_id.to_def_id()) + } else { + None + } + }) + }, + ItemKind::Enum(_, _, rustc_hir::EnumDef { variants }) if ns == PathNS::Type => { + variants.iter().find_map(|variant| { + if variant.ident.name == name { + Some(variant.def_id.to_def_id()) + } else { + None + } + }) + }, _ => None, } } @@ -336,6 +371,11 @@ fn non_local_item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, ns: PathNS, name .iter() .copied() .find(|&assoc_def_id| tcx.item_name(assoc_def_id) == name && ns.matches(tcx.def_kind(assoc_def_id).ns())), + DefKind::Struct => tcx + .associated_item_def_ids(def_id) + .iter() + .copied() + .find(|&assoc_def_id| tcx.item_name(assoc_def_id) == name), _ => None, } } diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 3ade38bea8ed6..641c6684a0bd1 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -370,6 +370,20 @@ impl<'a> Sugg<'a> { } } + /// Strip enclosing parentheses if present. This method must be called when + /// it is known that removing those will not change the meaning. For example, + /// if `self` is known to represent a reference and the suggestion will be + /// used as the argument of a function call, it is safe to remove the enclosing + /// parentheses. It would not be safe to do so for an expression that might + /// represent a tuple. + #[must_use] + pub fn strip_paren(self) -> Self { + match self { + Sugg::NonParen(s) | Sugg::MaybeParen(s) => Sugg::NonParen(strip_enclosing_paren(s)), + sugg => sugg, + } + } + pub fn into_string(self) -> String { match self { Sugg::NonParen(p) | Sugg::MaybeParen(p) => p.into_owned(), @@ -430,6 +444,22 @@ pub fn has_enclosing_paren(sugg: impl AsRef) -> bool { } } +/// Strip enclosing parentheses from a snippet if present. +fn strip_enclosing_paren(snippet: Cow<'_, str>) -> Cow<'_, str> { + if has_enclosing_paren(&snippet) { + match snippet { + Cow::Borrowed(s) => Cow::Borrowed(&s[1..s.len() - 1]), + Cow::Owned(mut s) => { + s.pop(); + s.remove(0); + Cow::Owned(s) + }, + } + } else { + snippet + } +} + /// Copied from the rust standard library, and then edited macro_rules! forward_binop_impls_to_ref { (impl $imp:ident, $method:ident for $t:ty, type Output = $o:ty) => { diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs index 6965225c12ab9..250e73afd4f00 100644 --- a/src/tools/clippy/clippy_utils/src/sym.rs +++ b/src/tools/clippy/clippy_utils/src/sym.rs @@ -285,11 +285,14 @@ generate! { from_millis, from_mins, from_nanos, + from_nanos_u128, from_ne_bytes, from_ptr, from_raw, from_raw_parts, from_secs, + from_secs_f32, + from_secs_f64, from_str_method, from_str_radix, from_weeks, diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index 36410a81fbf65..a9e29987bc32e 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -114,16 +114,15 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' match predicate.kind().skip_binder() { // For `impl Trait`, it will register a predicate of `T: Trait`, so we go through // and check substitutions to find `U`. - ty::ClauseKind::Trait(trait_predicate) => { + ty::ClauseKind::Trait(trait_predicate) if trait_predicate .trait_ref .args .types() .skip(1) // Skip the implicit `Self` generic parameter - .any(|ty| contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen)) - { - return true; - } + .any(|ty| contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen)) => + { + return true; }, // For `impl Trait`, it will register a predicate of `::Assoc = U`, // so we check the term for `U`. @@ -308,19 +307,29 @@ pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { } } -// Returns whether the type has #[must_use] attribute +// Returns whether the `ty` has `#[must_use]` attribute. If `ty` is a `Result`/`ControlFlow` +// whose `Err`/`Break` payload is an uninhabited type, the `Ok`/`Continue` payload type +// will be used instead. See . pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - match *ty.kind() { - ty::Adt(adt, _) => find_attr!(cx.tcx, adt.did(), MustUse { .. }), - ty::Foreign(did) => find_attr!(cx.tcx, did, MustUse { .. }), + match ty.kind() { + ty::Adt(adt, args) => match cx.tcx.get_diagnostic_name(adt.did()) { + Some(sym::Result) if args.type_at(1).is_privately_uninhabited(cx.tcx, cx.typing_env()) => { + is_must_use_ty(cx, args.type_at(0)) + }, + Some(sym::ControlFlow) if args.type_at(0).is_privately_uninhabited(cx.tcx, cx.typing_env()) => { + is_must_use_ty(cx, args.type_at(1)) + }, + _ => find_attr!(cx.tcx, adt.did(), MustUse { .. }), + }, + ty::Foreign(did) => find_attr!(cx.tcx, *did, MustUse { .. }), ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => { // for the Array case we don't need to care for the len == 0 case // because we don't want to lint functions returning empty arrays - is_must_use_ty(cx, ty) + is_must_use_ty(cx, *ty) }, ty::Tuple(args) => args.iter().any(|ty| is_must_use_ty(cx, ty)), ty::Alias(ty::Opaque, AliasTy { def_id, .. }) => { - for (predicate, _) in cx.tcx.explicit_item_self_bounds(def_id).skip_binder() { + for (predicate, _) in cx.tcx.explicit_item_self_bounds(*def_id).skip_binder() { if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() && find_attr!(cx.tcx, trait_predicate.trait_ref.def_id, MustUse { .. }) { @@ -330,7 +339,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { false }, ty::Dynamic(binder, _) => { - for predicate in binder { + for predicate in *binder { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() && find_attr!(cx.tcx, trait_ref.def_id, MustUse { .. }) { @@ -1262,6 +1271,13 @@ pub fn get_field_by_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, name: Symbol) -> } } +pub fn get_field_def_id_by_name(ty: Ty<'_>, name: Symbol) -> Option { + let ty::Adt(adt_def, ..) = ty.kind() else { return None }; + adt_def + .all_fields() + .find_map(|field| if field.name == name { Some(field.did) } else { None }) +} + /// Check if `ty` is an `Option` and return its argument type if it is. pub fn option_arg_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { match *ty.kind() { diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml index 558f808a7a3ed..e9b06bcbdaefa 100644 --- a/src/tools/clippy/rust-toolchain.toml +++ b/src/tools/clippy/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2026-02-11" +channel = "nightly-2026-02-19" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index 409eb182fe33c..f27cb67087096 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -126,6 +126,7 @@ impl rustc_driver::Callbacks for RustcCallbacks { config.psess_created = Some(Box::new(move |psess| { track_clippy_args(psess, clippy_args_var.as_deref()); })); + config.extra_symbols = sym::EXTRA_SYMBOLS.into(); } } diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index fa2b6cf268063..a92bb8f5ca734 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -469,7 +469,7 @@ enum DiagnosticOrMessage { } /// Collects applicabilities from the diagnostics produced for each UI test, producing the -/// `util/gh-pages/lints.json` file used by +/// `util/gh-pages/index.html` file used by #[derive(Debug, Clone)] struct DiagnosticCollector { sender: Sender>, diff --git a/src/tools/clippy/tests/missing-test-files.rs b/src/tools/clippy/tests/missing-test-files.rs index 9fff3132498d8..dbb25ac545fc3 100644 --- a/src/tools/clippy/tests/missing-test-files.rs +++ b/src/tools/clippy/tests/missing-test-files.rs @@ -53,10 +53,8 @@ fn explore_directory(dir: &Path) -> Vec { if let Some(ext) = path.extension() { match ext.to_str().unwrap() { "rs" | "toml" => current_file.clone_from(&file_prefix), - "stderr" | "stdout" => { - if file_prefix != current_file { - missing_files.push(path.to_str().unwrap().to_string()); - } + "stderr" | "stdout" if file_prefix != current_file => { + missing_files.push(path.to_str().unwrap().to_string()); }, _ => {}, } diff --git a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs index 4a179cd929f07..673a2d1676527 100644 --- a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs +++ b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs @@ -39,9 +39,4 @@ fn block_bad() -> impl std::future::Future { } } -fn main() { - good(); - bad(); - bad_reason(); - block_bad(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs index 9955c9b6baa1d..143b2cd280353 100644 --- a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs +++ b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs @@ -1,5 +1,4 @@ //@compile-flags: --test -//@no-rustfix #![warn(clippy::expect_used)] #![allow(clippy::unnecessary_literal_unwrap)] @@ -16,9 +15,6 @@ fn expect_result() { } fn main() { - expect_option(); - expect_result(); - const SOME: Option = Some(3); const UNWRAPPED: i32 = SOME.expect("Not three?"); //~^ expect_used diff --git a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr index 3bb471e6dfcc8..b794c2fc42fc8 100644 --- a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr +++ b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr @@ -1,5 +1,5 @@ error: used `expect()` on an `Option` value - --> tests/ui-toml/expect_used/expect_used.rs:8:13 + --> tests/ui-toml/expect_used/expect_used.rs:7:13 | LL | let _ = opt.expect(""); | ^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | let _ = opt.expect(""); = help: to override `-D warnings` add `#[allow(clippy::expect_used)]` error: used `expect()` on a `Result` value - --> tests/ui-toml/expect_used/expect_used.rs:14:13 + --> tests/ui-toml/expect_used/expect_used.rs:13:13 | LL | let _ = res.expect(""); | ^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | let _ = res.expect(""); = note: if this value is an `Err`, it will panic error: used `expect()` on an `Option` value - --> tests/ui-toml/expect_used/expect_used.rs:23:28 + --> tests/ui-toml/expect_used/expect_used.rs:19:28 | LL | const UNWRAPPED: i32 = SOME.expect("Not three?"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | const UNWRAPPED: i32 = SOME.expect("Not three?"); = note: if this value is `None`, it will panic error: used `expect()` on an `Option` value - --> tests/ui-toml/expect_used/expect_used.rs:26:9 + --> tests/ui-toml/expect_used/expect_used.rs:22:9 | LL | SOME.expect("Still not three?"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.fixed b/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.fixed index 2d76824128bfe..47a61122c9bc2 100644 --- a/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.fixed +++ b/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.fixed @@ -7,8 +7,6 @@ fn allow_inconsistent_digit_grouping() { } fn main() { - allow_inconsistent_digit_grouping(); - let _pass1 = 100_200_300.100_200_300; let _pass2 = 1.123456789; let _pass3 = 1.0; diff --git a/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.rs b/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.rs index b42e31085217f..eca273274d0d9 100644 --- a/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.rs +++ b/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.rs @@ -7,8 +7,6 @@ fn allow_inconsistent_digit_grouping() { } fn main() { - allow_inconsistent_digit_grouping(); - let _pass1 = 100_200_300.100_200_300; let _pass2 = 1.123456789; let _pass3 = 1.0; diff --git a/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.stderr b/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.stderr index c4e164c67ed89..e010e1e4d2fd4 100644 --- a/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.stderr +++ b/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.stderr @@ -1,5 +1,5 @@ error: digits grouped inconsistently by underscores - --> tests/ui-toml/lint_decimal_readability/test.rs:19:18 + --> tests/ui-toml/lint_decimal_readability/test.rs:17:18 | LL | let _fail1 = 100_200_300.123456789; | ^^^^^^^^^^^^^^^^^^^^^ help: consider: `100_200_300.123_456_789` @@ -8,7 +8,7 @@ LL | let _fail1 = 100_200_300.123456789; = help: to override `-D warnings` add `#[allow(clippy::inconsistent_digit_grouping)]` error: long literal lacking separators - --> tests/ui-toml/lint_decimal_readability/test.rs:23:18 + --> tests/ui-toml/lint_decimal_readability/test.rs:21:18 | LL | let _fail2 = 100200300.300200100; | ^^^^^^^^^^^^^^^^^^^ help: consider: `100_200_300.300_200_100` diff --git a/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed b/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed index 36540bf1dcf73..92c356b9b277d 100644 --- a/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed +++ b/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed @@ -18,7 +18,4 @@ fn above_limit() { } } -fn main() { - below_limit(); - above_limit(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs b/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs index da76bb20fd961..3bf743c256641 100644 --- a/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs +++ b/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs @@ -18,7 +18,4 @@ fn above_limit() { } } -fn main() { - below_limit(); - above_limit(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.fixed b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.fixed index 685f77b7efe82..d73da96543d72 100644 --- a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.fixed +++ b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.fixed @@ -88,12 +88,4 @@ fn manual_bits() { size_of_val(&0u32) * 8; } -fn main() { - option_as_ref_deref(); - match_like_matches(); - match_same_arms(); - match_same_arms2(); - manual_strip_msrv(); - check_index_refutable_slice(); - borrow_as_ptr(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs index 0bf073af89032..78cfba1189fbf 100644 --- a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs +++ b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs @@ -88,12 +88,4 @@ fn manual_bits() { size_of_val(&0u32) * 8; } -fn main() { - option_as_ref_deref(); - match_like_matches(); - match_same_arms(); - match_same_arms2(); - manual_strip_msrv(); - check_index_refutable_slice(); - borrow_as_ptr(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs b/src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs index b23c2340b7d63..aca6c6f841138 100644 --- a/src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs +++ b/src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs @@ -56,7 +56,4 @@ fn should_not_take_this_arg(_v: HashSet>) {} fn indirect(_: HashMap) {} -fn main() { - should_not_take_this_arg(HashSet::new()); - indirect(HashMap::new()); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_fields/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_disallowed_fields/clippy.toml new file mode 100644 index 0000000000000..615d405a87a49 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_fields/clippy.toml @@ -0,0 +1,14 @@ +disallowed-fields = [ + # just a string is shorthand for path only + "std::ops::Range::start", + # can give path and reason with an inline table + { path = "std::ops::Range::end", reason = "no end allowed" }, + # can use an inline table but omit reason + { path = "std::ops::RangeTo::end" }, + # local paths + "conf_disallowed_fields::X::y", + # re-exports + "conf_disallowed_fields::Y::y", + # field of a variant + "conf_disallowed_fields::Z::B::x", +] diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs b/src/tools/clippy/tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs new file mode 100644 index 0000000000000..7804b605a67a6 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs @@ -0,0 +1,50 @@ +#![warn(clippy::disallowed_fields)] +#![allow(clippy::match_single_binding)] + +use std::ops::{Range, RangeTo}; + +struct X { + y: u32, +} + +enum Z { + A { x: u32 }, + B { x: u32 }, +} + +use crate::X as Y; + +fn b(X { y }: X) {} +//~^ disallowed_fields + +fn main() { + let x = X { y: 0 }; + let _ = x.y; + //~^ disallowed_fields + + let x = Y { y: 0 }; + let _ = x.y; + //~^ disallowed_fields + + let x = Range { start: 0, end: 0 }; + let _ = x.start; + //~^ disallowed_fields + let _ = x.end; + //~^ disallowed_fields + let Range { start, .. } = x; + //~^ disallowed_fields + + let x = RangeTo { end: 0 }; + let _ = x.end; + //~^ disallowed_fields + + match x { + RangeTo { end } => {}, //~ disallowed_fields + } + + let x = Z::B { x: 0 }; + match x { + Z::A { x } => {}, + Z::B { x } => {}, //~ disallowed_fields + } +} diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.stderr b/src/tools/clippy/tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.stderr new file mode 100644 index 0000000000000..ac43c702bbdc1 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.stderr @@ -0,0 +1,61 @@ +error: use of a disallowed field `conf_disallowed_fields::Y::y` + --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:17:10 + | +LL | fn b(X { y }: X) {} + | ^ + | + = note: `-D clippy::disallowed-fields` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::disallowed_fields)]` + +error: use of a disallowed field `conf_disallowed_fields::Y::y` + --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:22:15 + | +LL | let _ = x.y; + | ^ + +error: use of a disallowed field `conf_disallowed_fields::Y::y` + --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:26:15 + | +LL | let _ = x.y; + | ^ + +error: use of a disallowed field `std::ops::Range::start` + --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:30:15 + | +LL | let _ = x.start; + | ^^^^^ + +error: use of a disallowed field `std::ops::Range::end` + --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:32:15 + | +LL | let _ = x.end; + | ^^^ + | + = note: no end allowed + +error: use of a disallowed field `std::ops::Range::start` + --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:34:17 + | +LL | let Range { start, .. } = x; + | ^^^^^ + +error: use of a disallowed field `std::ops::RangeTo::end` + --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:38:15 + | +LL | let _ = x.end; + | ^^^ + +error: use of a disallowed field `std::ops::RangeTo::end` + --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:42:19 + | +LL | RangeTo { end } => {}, + | ^^^ + +error: use of a disallowed field `conf_disallowed_fields::Z::B::x` + --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:48:16 + | +LL | Z::B { x } => {}, + | ^ + +error: aborting due to 9 previous errors + diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index e208bd510657e..6bb3db8db67f0 100644 --- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -18,6 +18,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect allow-renamed-params-for allow-unwrap-in-consts allow-unwrap-in-tests + allow-unwrap-types allow-useless-vec-in-tests allowed-dotfiles allowed-duplicate-crates @@ -37,6 +38,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect check-private-items cognitive-complexity-threshold const-literal-digits-threshold + disallowed-fields disallowed-macros disallowed-methods disallowed-names @@ -117,6 +119,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect allow-renamed-params-for allow-unwrap-in-consts allow-unwrap-in-tests + allow-unwrap-types allow-useless-vec-in-tests allowed-dotfiles allowed-duplicate-crates @@ -136,6 +139,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect check-private-items cognitive-complexity-threshold const-literal-digits-threshold + disallowed-fields disallowed-macros disallowed-methods disallowed-names @@ -216,6 +220,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni allow-renamed-params-for allow-unwrap-in-consts allow-unwrap-in-tests + allow-unwrap-types allow-useless-vec-in-tests allowed-dotfiles allowed-duplicate-crates @@ -235,6 +240,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni check-private-items cognitive-complexity-threshold const-literal-digits-threshold + disallowed-fields disallowed-macros disallowed-methods disallowed-names diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used_allowed/clippy.toml b/src/tools/clippy/tests/ui-toml/unwrap_used_allowed/clippy.toml new file mode 100644 index 0000000000000..cceb303c126fa --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/unwrap_used_allowed/clippy.toml @@ -0,0 +1 @@ +allow-unwrap-types = ["std::sync::LockResult"] \ No newline at end of file diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used_allowed/unwrap_used_allowed.rs b/src/tools/clippy/tests/ui-toml/unwrap_used_allowed/unwrap_used_allowed.rs new file mode 100644 index 0000000000000..7905674e21e7f --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/unwrap_used_allowed/unwrap_used_allowed.rs @@ -0,0 +1,20 @@ +#![warn(clippy::unwrap_used)] +#![allow(clippy::unnecessary_literal_unwrap)] +#![allow(unused_variables)] +use std::sync::Mutex; + +fn main() { + let m = Mutex::new(0); + // This is allowed because `LockResult` is configured! + let _guard = m.lock().unwrap(); + + let optional: Option = Some(1); + // This is not allowed! + let _opt = optional.unwrap(); + //~^ ERROR: used `unwrap()` on an `Option` value + + let result: Result = Ok(1); + // This is not allowed! + let _res = result.unwrap(); + //~^ ERROR: used `unwrap()` on a `Result` value +} diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used_allowed/unwrap_used_allowed.stderr b/src/tools/clippy/tests/ui-toml/unwrap_used_allowed/unwrap_used_allowed.stderr new file mode 100644 index 0000000000000..1df89bf2eb92a --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/unwrap_used_allowed/unwrap_used_allowed.stderr @@ -0,0 +1,22 @@ +error: used `unwrap()` on an `Option` value + --> tests/ui-toml/unwrap_used_allowed/unwrap_used_allowed.rs:13:16 + | +LL | let _opt = optional.unwrap(); + | ^^^^^^^^^^^^^^^^^ + | + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message + = note: `-D clippy::unwrap-used` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]` + +error: used `unwrap()` on a `Result` value + --> tests/ui-toml/unwrap_used_allowed/unwrap_used_allowed.rs:18:16 + | +LL | let _res = result.unwrap(); + | ^^^^^^^^^^^^^^^ + | + = note: if this value is an `Err`, it will panic + = help: consider using `expect()` to provide a better panic message + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/attrs.rs b/src/tools/clippy/tests/ui/attrs.rs index f60c71837d5e9..128fb6f5e38d2 100644 --- a/src/tools/clippy/tests/ui/attrs.rs +++ b/src/tools/clippy/tests/ui/attrs.rs @@ -37,15 +37,4 @@ pub const YET_ANOTHER_CONST: u8 = 0; #[deprecated(since = "TBD")] pub const GONNA_DEPRECATE_THIS_LATER: u8 = 0; -fn main() { - test_attr_lint(); - if false { - false_positive_expr() - } - if false { - false_positive_stmt() - } - if false { - empty_and_false_positive_stmt() - } -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.fixed b/src/tools/clippy/tests/ui/borrow_deref_ref.fixed index 6d06fcc3037aa..60334922a08a7 100644 --- a/src/tools/clippy/tests/ui/borrow_deref_ref.fixed +++ b/src/tools/clippy/tests/ui/borrow_deref_ref.fixed @@ -171,3 +171,27 @@ fn issue_14934() { //~^ borrow_deref_ref } } + +mod issue16556 { + use std::pin::Pin; + + async fn async_main() { + for_each_city(|city| { + Box::pin(async { + // Do not lint, as it would not compile without reborrowing + let city = &*city; + println!("{city}") + }) + }) + .await; + } + + async fn for_each_city(mut f: F) + where + F: for<'c> FnMut(&'c str) -> Pin + Send + 'c>>, + { + for x in ["New York", "London", "Tokyo"] { + f(x).await; + } + } +} diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.rs b/src/tools/clippy/tests/ui/borrow_deref_ref.rs index b43f4c93bf2b0..99fd1ae0acbc2 100644 --- a/src/tools/clippy/tests/ui/borrow_deref_ref.rs +++ b/src/tools/clippy/tests/ui/borrow_deref_ref.rs @@ -171,3 +171,27 @@ fn issue_14934() { //~^ borrow_deref_ref } } + +mod issue16556 { + use std::pin::Pin; + + async fn async_main() { + for_each_city(|city| { + Box::pin(async { + // Do not lint, as it would not compile without reborrowing + let city = &*city; + println!("{city}") + }) + }) + .await; + } + + async fn for_each_city(mut f: F) + where + F: for<'c> FnMut(&'c str) -> Pin + Send + 'c>>, + { + for x in ["New York", "London", "Tokyo"] { + f(x).await; + } + } +} diff --git a/src/tools/clippy/tests/ui/clone_on_ref_ptr.fixed b/src/tools/clippy/tests/ui/clone_on_ref_ptr.fixed index ede9d171517e7..86ae237f09af3 100644 --- a/src/tools/clippy/tests/ui/clone_on_ref_ptr.fixed +++ b/src/tools/clippy/tests/ui/clone_on_ref_ptr.fixed @@ -50,10 +50,6 @@ mod issue2076 { } } -#[allow( - clippy::needless_borrow, - reason = "the suggestion creates `Weak::clone(&rec)`, but `rec` is already a reference" -)] mod issue15009 { use std::rc::{Rc, Weak}; use std::sync::atomic::{AtomicU32, Ordering}; @@ -62,7 +58,7 @@ mod issue15009 { let counter = AtomicU32::new(0); let counter_ref = &counter; let factorial = Rc::new_cyclic(move |rec| { - let rec = std::rc::Weak::::clone(&rec) as Weak u32>; + let rec = std::rc::Weak::::clone(rec) as Weak u32>; //~^ clone_on_ref_ptr move |x| { // can capture env @@ -79,3 +75,26 @@ mod issue15009 { println!("{}", counter.load(Ordering::Relaxed)); // 14 } } + +fn issue15741(mut rc: Rc, ref_rc: &Rc, refmut_rc: &mut Rc) { + std::rc::Rc::::clone(&rc); + //~^ clone_on_ref_ptr + std::rc::Rc::::clone(ref_rc); + //~^ clone_on_ref_ptr + std::rc::Rc::::clone(refmut_rc); + //~^ clone_on_ref_ptr + + // The following cases already cause warn-by-default lints to fire, and the suggestion just makes + // another set of warn-by-default lints to fire, so this is probably fine + + #[allow(clippy::needless_borrow, clippy::unnecessary_mut_passed)] // before the suggestion + #[allow(clippy::double_parens)] // after the suggestion + { + std::rc::Rc::::clone(&(rc)); + //~^ clone_on_ref_ptr + std::rc::Rc::::clone(&rc); + //~^ clone_on_ref_ptr + std::rc::Rc::::clone(&mut rc); + //~^ clone_on_ref_ptr + }; +} diff --git a/src/tools/clippy/tests/ui/clone_on_ref_ptr.rs b/src/tools/clippy/tests/ui/clone_on_ref_ptr.rs index 5999b4069d0f2..cc6d2b6115753 100644 --- a/src/tools/clippy/tests/ui/clone_on_ref_ptr.rs +++ b/src/tools/clippy/tests/ui/clone_on_ref_ptr.rs @@ -50,10 +50,6 @@ mod issue2076 { } } -#[allow( - clippy::needless_borrow, - reason = "the suggestion creates `Weak::clone(&rec)`, but `rec` is already a reference" -)] mod issue15009 { use std::rc::{Rc, Weak}; use std::sync::atomic::{AtomicU32, Ordering}; @@ -79,3 +75,26 @@ mod issue15009 { println!("{}", counter.load(Ordering::Relaxed)); // 14 } } + +fn issue15741(mut rc: Rc, ref_rc: &Rc, refmut_rc: &mut Rc) { + rc.clone(); + //~^ clone_on_ref_ptr + ref_rc.clone(); + //~^ clone_on_ref_ptr + refmut_rc.clone(); + //~^ clone_on_ref_ptr + + // The following cases already cause warn-by-default lints to fire, and the suggestion just makes + // another set of warn-by-default lints to fire, so this is probably fine + + #[allow(clippy::needless_borrow, clippy::unnecessary_mut_passed)] // before the suggestion + #[allow(clippy::double_parens)] // after the suggestion + { + (rc).clone(); + //~^ clone_on_ref_ptr + (&rc).clone(); + //~^ clone_on_ref_ptr + (&mut rc).clone(); + //~^ clone_on_ref_ptr + }; +} diff --git a/src/tools/clippy/tests/ui/clone_on_ref_ptr.stderr b/src/tools/clippy/tests/ui/clone_on_ref_ptr.stderr index b8ddc3058c012..6a151e9ee101d 100644 --- a/src/tools/clippy/tests/ui/clone_on_ref_ptr.stderr +++ b/src/tools/clippy/tests/ui/clone_on_ref_ptr.stderr @@ -38,10 +38,46 @@ LL | Some(try_opt!(Some(rc)).clone()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::rc::Rc::::clone(&try_opt!(Some(rc)))` error: using `.clone()` on a ref-counted pointer - --> tests/ui/clone_on_ref_ptr.rs:65:23 + --> tests/ui/clone_on_ref_ptr.rs:61:23 | LL | let rec = rec.clone() as Weak u32>; - | ^^^^^^^^^^^ help: try: `std::rc::Weak::::clone(&rec)` + | ^^^^^^^^^^^ help: try: `std::rc::Weak::::clone(rec)` -error: aborting due to 7 previous errors +error: using `.clone()` on a ref-counted pointer + --> tests/ui/clone_on_ref_ptr.rs:80:5 + | +LL | rc.clone(); + | ^^^^^^^^^^ help: try: `std::rc::Rc::::clone(&rc)` + +error: using `.clone()` on a ref-counted pointer + --> tests/ui/clone_on_ref_ptr.rs:82:5 + | +LL | ref_rc.clone(); + | ^^^^^^^^^^^^^^ help: try: `std::rc::Rc::::clone(ref_rc)` + +error: using `.clone()` on a ref-counted pointer + --> tests/ui/clone_on_ref_ptr.rs:84:5 + | +LL | refmut_rc.clone(); + | ^^^^^^^^^^^^^^^^^ help: try: `std::rc::Rc::::clone(refmut_rc)` + +error: using `.clone()` on a ref-counted pointer + --> tests/ui/clone_on_ref_ptr.rs:93:9 + | +LL | (rc).clone(); + | ^^^^^^^^^^^^ help: try: `std::rc::Rc::::clone(&(rc))` + +error: using `.clone()` on a ref-counted pointer + --> tests/ui/clone_on_ref_ptr.rs:95:9 + | +LL | (&rc).clone(); + | ^^^^^^^^^^^^^ help: try: `std::rc::Rc::::clone(&rc)` + +error: using `.clone()` on a ref-counted pointer + --> tests/ui/clone_on_ref_ptr.rs:97:9 + | +LL | (&mut rc).clone(); + | ^^^^^^^^^^^^^^^^^ help: try: `std::rc::Rc::::clone(&mut rc)` + +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed index f65339605e756..471905b47df7f 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed +++ b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed @@ -114,6 +114,12 @@ fn issue16322(item: String) { } fn issue16458() { + macro_rules! m { + () => { + "" + }; + } + macro_rules! partly_comes_from_macro { ($i:ident: $ty:ty, $def:expr) => { let _ = { @@ -125,7 +131,7 @@ fn issue16458() { } partly_comes_from_macro! { - required_version: String, env!("HOME").to_string() + required_version: String, m!().to_string() } macro_rules! all_comes_from_macro { @@ -141,6 +147,6 @@ fn issue16458() { }; } all_comes_from_macro! { - required_version: String, env!("HOME").to_string(); + required_version: String, m!().to_string(); } } diff --git a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs index ed2300c80eaa9..3323176d34e39 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs +++ b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs @@ -114,6 +114,12 @@ fn issue16322(item: String) { } fn issue16458() { + macro_rules! m { + () => { + "" + }; + } + macro_rules! partly_comes_from_macro { ($i:ident: $ty:ty, $def:expr) => { let _ = { @@ -125,7 +131,7 @@ fn issue16458() { } partly_comes_from_macro! { - required_version: String, env!("HOME").to_string() + required_version: String, m!().to_string() } macro_rules! all_comes_from_macro { @@ -141,6 +147,6 @@ fn issue16458() { }; } all_comes_from_macro! { - required_version: String, env!("HOME").to_string(); + required_version: String, m!().to_string(); } } diff --git a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.stderr b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.stderr index 38d124baa4b56..3797810e3b982 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.stderr +++ b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.stderr @@ -56,13 +56,13 @@ LL | if item == t!(frohes_neu_Jahr).to_string() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t!(frohes_neu_Jahr)` error: this creates an owned instance just for comparison - --> tests/ui/cmp_owned/with_suggestion.rs:135:51 + --> tests/ui/cmp_owned/with_suggestion.rs:141:51 | LL | let res = <$ty>::default() == "$def".to_string(); | ^^^^^^^^^^^^^^^^^^ help: try: `"$def"` ... LL | / all_comes_from_macro! { -LL | | required_version: String, env!("HOME").to_string(); +LL | | required_version: String, m!().to_string(); LL | | } | |_____- in this macro invocation | diff --git a/src/tools/clippy/tests/ui/collapsible_match_fixable.fixed b/src/tools/clippy/tests/ui/collapsible_match_fixable.fixed new file mode 100644 index 0000000000000..db76530aee144 --- /dev/null +++ b/src/tools/clippy/tests/ui/collapsible_match_fixable.fixed @@ -0,0 +1,30 @@ +#![warn(clippy::collapsible_match)] +#![allow(clippy::single_match, clippy::redundant_guards)] + +fn issue16558() { + let opt = Some(1); + let _ = match opt { + Some(s) + if s == 1 => { s } + //~^ collapsible_match + , + _ => 1, + }; + + match opt { + Some(s) + if s == 1 => { + //~^ collapsible_match + todo!() + }, + _ => {}, + }; + + let _ = match opt { + Some(s) if s > 2 + && s == 1 => { s } + //~^ collapsible_match + , + _ => 1, + }; +} diff --git a/src/tools/clippy/tests/ui/collapsible_match_fixable.rs b/src/tools/clippy/tests/ui/collapsible_match_fixable.rs new file mode 100644 index 0000000000000..94bf1d6bfdfab --- /dev/null +++ b/src/tools/clippy/tests/ui/collapsible_match_fixable.rs @@ -0,0 +1,31 @@ +#![warn(clippy::collapsible_match)] +#![allow(clippy::single_match, clippy::redundant_guards)] + +fn issue16558() { + let opt = Some(1); + let _ = match opt { + Some(s) => { + if s == 1 { s } else { 1 } + //~^ collapsible_match + }, + _ => 1, + }; + + match opt { + Some(s) => { + (if s == 1 { + //~^ collapsible_match + todo!() + }) + }, + _ => {}, + }; + + let _ = match opt { + Some(s) if s > 2 => { + if s == 1 { s } else { 1 } + //~^ collapsible_match + }, + _ => 1, + }; +} diff --git a/src/tools/clippy/tests/ui/collapsible_match_fixable.stderr b/src/tools/clippy/tests/ui/collapsible_match_fixable.stderr new file mode 100644 index 0000000000000..4d501cbd0993d --- /dev/null +++ b/src/tools/clippy/tests/ui/collapsible_match_fixable.stderr @@ -0,0 +1,50 @@ +error: this `if` can be collapsed into the outer `match` + --> tests/ui/collapsible_match_fixable.rs:8:13 + | +LL | if s == 1 { s } else { 1 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::collapsible-match` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::collapsible_match)]` +help: collapse nested if block + | +LL ~ Some(s) +LL ~ if s == 1 => { s } +LL | +LL ~ , + | + +error: this `if` can be collapsed into the outer `match` + --> tests/ui/collapsible_match_fixable.rs:16:13 + | +LL | / (if s == 1 { +LL | | +LL | | todo!() +LL | | }) + | |______________^ + | +help: collapse nested if block + | +LL ~ Some(s) +LL ~ if s == 1 => { +LL | +LL | todo!() +LL ~ }, + | + +error: this `if` can be collapsed into the outer `match` + --> tests/ui/collapsible_match_fixable.rs:26:13 + | +LL | if s == 1 { s } else { 1 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: collapse nested if block + | +LL ~ Some(s) if s > 2 +LL ~ && s == 1 => { s } +LL | +LL ~ , + | + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/crashes/ice-10912.rs b/src/tools/clippy/tests/ui/crashes/ice-10912.rs index 1d689e1d0082d..57403d98e5d0a 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-10912.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-10912.rs @@ -1,5 +1,5 @@ #![warn(clippy::unreadable_literal)] -//@no-rustfix + fn f2() -> impl Sized { && 3.14159265358979323846E } //~^ ERROR: expected at least one digit in exponent diff --git a/src/tools/clippy/tests/ui/crashes/ice-6250.fixed b/src/tools/clippy/tests/ui/crashes/ice-6250.fixed new file mode 100644 index 0000000000000..71b3c90d56b0e --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-6250.fixed @@ -0,0 +1,19 @@ +// originally from glacier/fixed/77218.rs +// ice while adjusting... +#![expect(clippy::useless_vec)] + +pub struct Cache { + data: Vec, +} + +pub fn list_data(cache: &Cache, key: usize) { + for reference in vec![1, 2, 3] { + if + /* let */ + let Some(reference) = cache.data.get(key) { + //~^ ERROR: mismatched types + //~| ERROR: mismatched types + unimplemented!() + } + } +} diff --git a/src/tools/clippy/tests/ui/crashes/ice-6250.rs b/src/tools/clippy/tests/ui/crashes/ice-6250.rs index 65cdce7931429..8c6100e2054df 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6250.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-6250.rs @@ -1,6 +1,7 @@ // originally from glacier/fixed/77218.rs // ice while adjusting... -//@no-rustfix +#![expect(clippy::useless_vec)] + pub struct Cache { data: Vec, } diff --git a/src/tools/clippy/tests/ui/crashes/ice-6250.stderr b/src/tools/clippy/tests/ui/crashes/ice-6250.stderr index c126547611f36..83a7ef9fd2cf0 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6250.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-6250.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> tests/ui/crashes/ice-6250.rs:12:14 + --> tests/ui/crashes/ice-6250.rs:13:14 | LL | for reference in vec![1, 2, 3] { | --------- expected due to the type of this binding @@ -8,7 +8,7 @@ LL | Some(reference) = cache.data.get(key) { | ^^^^^^^^^ expected integer, found `&i32` error[E0308]: mismatched types - --> tests/ui/crashes/ice-6250.rs:12:9 + --> tests/ui/crashes/ice-6250.rs:13:9 | LL | Some(reference) = cache.data.get(key) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()` diff --git a/src/tools/clippy/tests/ui/crashes/ice-9041.fixed b/src/tools/clippy/tests/ui/crashes/ice-9041.fixed new file mode 100644 index 0000000000000..32399e4255d1d --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-9041.fixed @@ -0,0 +1,12 @@ +#![warn(clippy::search_is_some)] +#![allow(clippy::needless_borrow)] + +pub struct Thing; + +pub fn has_thing(things: &[Thing]) -> bool { + let is_thing_ready = |_peer: &Thing| -> bool { todo!() }; + things.iter().any(|p| is_thing_ready(&p)) + //~^ search_is_some +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-9041.rs b/src/tools/clippy/tests/ui/crashes/ice-9041.rs index fae3233ba2f51..55e88fa6da5af 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9041.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-9041.rs @@ -1,6 +1,8 @@ #![warn(clippy::search_is_some)] +#![allow(clippy::needless_borrow)] + pub struct Thing; -//@no-rustfix + pub fn has_thing(things: &[Thing]) -> bool { let is_thing_ready = |_peer: &Thing| -> bool { todo!() }; things.iter().find(|p| is_thing_ready(p)).is_some() diff --git a/src/tools/clippy/tests/ui/crashes/ice-9041.stderr b/src/tools/clippy/tests/ui/crashes/ice-9041.stderr index 256c8b8330344..98bdff9bbfac4 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9041.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-9041.stderr @@ -1,5 +1,5 @@ error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/crashes/ice-9041.rs:6:19 + --> tests/ui/crashes/ice-9041.rs:8:19 | LL | things.iter().find(|p| is_thing_ready(p)).is_some() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|p| is_thing_ready(&p))` diff --git a/src/tools/clippy/tests/ui/crashes/returns.rs b/src/tools/clippy/tests/ui/crashes/returns.rs index ccab9522753eb..a28266a2d2f1f 100644 --- a/src/tools/clippy/tests/ui/crashes/returns.rs +++ b/src/tools/clippy/tests/ui/crashes/returns.rs @@ -18,7 +18,4 @@ fn cfg_let_and_return() -> i32 { x } -fn main() { - cfg_return(); - cfg_let_and_return(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/debug_assert_with_mut_call.rs b/src/tools/clippy/tests/ui/debug_assert_with_mut_call.rs index 74d59b7593fa7..199f217a02b96 100644 --- a/src/tools/clippy/tests/ui/debug_assert_with_mut_call.rs +++ b/src/tools/clippy/tests/ui/debug_assert_with_mut_call.rs @@ -179,12 +179,4 @@ async fn debug_await() { }.await); } -fn main() { - func_non_mutable(); - func_mutable(); - method_non_mutable(); - method_mutable(); - - misc(); - debug_await(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed index 58d8b8b33ade0..570d8090f8e3e 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed @@ -109,10 +109,6 @@ fn test_allowed() { /// `be_sure_we_got_to_the_end_of_it` //~^ doc_markdown fn main() { - foo_bar(); - multiline_codeblock(); - test_emphasis(); - test_units(); } /// ## `CamelCaseThing` diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs index 0b1237f716fa0..dd80bc4b25eeb 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs @@ -109,10 +109,6 @@ fn test_allowed() { /// be_sure_we_got_to_the_end_of_it //~^ doc_markdown fn main() { - foo_bar(); - multiline_codeblock(); - test_emphasis(); - test_units(); } /// ## CamelCaseThing diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr index 2a94a8f316587..a04d06f6db1ab 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr @@ -169,7 +169,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:118:8 + --> tests/ui/doc/doc-fixable.rs:114:8 | LL | /// ## CamelCaseThing | ^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + /// ## `CamelCaseThing` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:122:7 + --> tests/ui/doc/doc-fixable.rs:118:7 | LL | /// # CamelCaseThing | ^^^^^^^^^^^^^^ @@ -193,7 +193,7 @@ LL + /// # `CamelCaseThing` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:125:22 + --> tests/ui/doc/doc-fixable.rs:121:22 | LL | /// Not a title #897 CamelCaseThing | ^^^^^^^^^^^^^^ @@ -205,7 +205,7 @@ LL + /// Not a title #897 `CamelCaseThing` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:127:5 + --> tests/ui/doc/doc-fixable.rs:123:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -217,7 +217,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:135:5 + --> tests/ui/doc/doc-fixable.rs:131:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -229,7 +229,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:149:5 + --> tests/ui/doc/doc-fixable.rs:145:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,7 +241,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:161:43 + --> tests/ui/doc/doc-fixable.rs:157:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ @@ -253,7 +253,7 @@ LL + /** E.g., serialization of an empty list: `FooBar` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:166:5 + --> tests/ui/doc/doc-fixable.rs:162:5 | LL | And BarQuz too. | ^^^^^^ @@ -265,7 +265,7 @@ LL + And `BarQuz` too. | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:167:1 + --> tests/ui/doc/doc-fixable.rs:163:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -277,7 +277,7 @@ LL + `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:175:43 + --> tests/ui/doc/doc-fixable.rs:171:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ @@ -289,7 +289,7 @@ LL + /** E.g., serialization of an empty list: `FooBar` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:180:5 + --> tests/ui/doc/doc-fixable.rs:176:5 | LL | And BarQuz too. | ^^^^^^ @@ -301,7 +301,7 @@ LL + And `BarQuz` too. | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:181:1 + --> tests/ui/doc/doc-fixable.rs:177:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -313,7 +313,7 @@ LL + `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:195:5 + --> tests/ui/doc/doc-fixable.rs:191:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -325,7 +325,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:215:22 + --> tests/ui/doc/doc-fixable.rs:211:22 | LL | /// An iterator over mycrate::Collection's values. | ^^^^^^^^^^^^^^^^^^^ @@ -337,7 +337,7 @@ LL + /// An iterator over `mycrate::Collection`'s values. | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:240:34 + --> tests/ui/doc/doc-fixable.rs:236:34 | LL | /// Foo \[bar\] \[baz\] \[qux\]. DocMarkdownLint | ^^^^^^^^^^^^^^^ @@ -349,7 +349,7 @@ LL + /// Foo \[bar\] \[baz\] \[qux\]. `DocMarkdownLint` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:264:22 + --> tests/ui/doc/doc-fixable.rs:260:22 | LL | /// There is no try (do() or do_not()). | ^^^^ @@ -361,7 +361,7 @@ LL + /// There is no try (`do()` or do_not()). | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:264:30 + --> tests/ui/doc/doc-fixable.rs:260:30 | LL | /// There is no try (do() or do_not()). | ^^^^^^^^ @@ -373,7 +373,7 @@ LL + /// There is no try (do() or `do_not()`). | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:269:5 + --> tests/ui/doc/doc-fixable.rs:265:5 | LL | /// ABes | ^^^^ @@ -385,7 +385,7 @@ LL + /// `ABes` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:276:9 + --> tests/ui/doc/doc-fixable.rs:272:9 | LL | /// foo() | ^^^^^ @@ -397,7 +397,7 @@ LL + /// `foo()` | error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> tests/ui/doc/doc-fixable.rs:281:5 + --> tests/ui/doc/doc-fixable.rs:277:5 | LL | /// https://github.com/rust-lang/rust-clippy/pull/12836 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `` diff --git a/src/tools/clippy/tests/ui/doc_link_with_quotes.rs b/src/tools/clippy/tests/ui/doc_link_with_quotes.rs index 0c0e273da6db4..82ec8fc2e081c 100644 --- a/src/tools/clippy/tests/ui/doc_link_with_quotes.rs +++ b/src/tools/clippy/tests/ui/doc_link_with_quotes.rs @@ -1,8 +1,6 @@ #![warn(clippy::doc_link_with_quotes)] -fn main() { - foo() -} +fn main() {} /// Calls ['bar'] uselessly //~^ doc_link_with_quotes diff --git a/src/tools/clippy/tests/ui/doc_link_with_quotes.stderr b/src/tools/clippy/tests/ui/doc_link_with_quotes.stderr index 47c60390310c1..729fc483f5621 100644 --- a/src/tools/clippy/tests/ui/doc_link_with_quotes.stderr +++ b/src/tools/clippy/tests/ui/doc_link_with_quotes.stderr @@ -1,5 +1,5 @@ error: possible intra-doc link using quotes instead of backticks - --> tests/ui/doc_link_with_quotes.rs:7:12 + --> tests/ui/doc_link_with_quotes.rs:5:12 | LL | /// Calls ['bar'] uselessly | ^^^^^ @@ -8,7 +8,7 @@ LL | /// Calls ['bar'] uselessly = help: to override `-D warnings` add `#[allow(clippy::doc_link_with_quotes)]` error: possible intra-doc link using quotes instead of backticks - --> tests/ui/doc_link_with_quotes.rs:13:12 + --> tests/ui/doc_link_with_quotes.rs:11:12 | LL | /// Calls ["bar"] uselessly | ^^^^^ diff --git a/src/tools/clippy/tests/ui/double_must_use.rs b/src/tools/clippy/tests/ui/double_must_use.rs index 3d4aaa9baa49c..c8b5828889fc8 100644 --- a/src/tools/clippy/tests/ui/double_must_use.rs +++ b/src/tools/clippy/tests/ui/double_must_use.rs @@ -1,5 +1,8 @@ #![warn(clippy::double_must_use)] #![allow(clippy::result_unit_err)] +#![feature(never_type)] + +use std::ops::ControlFlow; #[must_use] pub fn must_use_result() -> Result<(), ()> { @@ -40,8 +43,29 @@ async fn async_must_use_result() -> Result<(), ()> { Ok(()) } -fn main() { - must_use_result(); - must_use_tuple(); - must_use_with_note(); +#[must_use] +pub fn must_use_result_with_uninhabited() -> Result<(), !> { + unimplemented!(); +} + +#[must_use] +pub struct T; + +#[must_use] +pub fn must_use_result_with_uninhabited_2() -> Result { + //~^ double_must_use + unimplemented!(); +} + +#[must_use] +pub fn must_use_controlflow_with_uninhabited() -> ControlFlow { + unimplemented!(); +} + +#[must_use] +pub fn must_use_controlflow_with_uninhabited_2() -> ControlFlow { + //~^ double_must_use + unimplemented!(); } + +fn main() {} diff --git a/src/tools/clippy/tests/ui/double_must_use.stderr b/src/tools/clippy/tests/ui/double_must_use.stderr index 555dd8902cac4..50b1640c47f5f 100644 --- a/src/tools/clippy/tests/ui/double_must_use.stderr +++ b/src/tools/clippy/tests/ui/double_must_use.stderr @@ -1,5 +1,5 @@ error: this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]` - --> tests/ui/double_must_use.rs:5:1 + --> tests/ui/double_must_use.rs:8:1 | LL | pub fn must_use_result() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | pub fn must_use_result() -> Result<(), ()> { = help: to override `-D warnings` add `#[allow(clippy::double_must_use)]` error: this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]` - --> tests/ui/double_must_use.rs:12:1 + --> tests/ui/double_must_use.rs:15:1 | LL | pub fn must_use_tuple() -> (Result<(), ()>, u8) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | pub fn must_use_tuple() -> (Result<(), ()>, u8) { = help: either add some descriptive message or remove the attribute error: this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]` - --> tests/ui/double_must_use.rs:19:1 + --> tests/ui/double_must_use.rs:22:1 | LL | pub fn must_use_array() -> [Result<(), ()>; 1] { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,12 +25,28 @@ LL | pub fn must_use_array() -> [Result<(), ()>; 1] { = help: either add some descriptive message or remove the attribute error: this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]` - --> tests/ui/double_must_use.rs:37:1 + --> tests/ui/double_must_use.rs:40:1 | LL | async fn async_must_use_result() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: either add some descriptive message or remove the attribute -error: aborting due to 4 previous errors +error: this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]` + --> tests/ui/double_must_use.rs:55:1 + | +LL | pub fn must_use_result_with_uninhabited_2() -> Result { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: either add some descriptive message or remove the attribute + +error: this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]` + --> tests/ui/double_must_use.rs:66:1 + | +LL | pub fn must_use_controlflow_with_uninhabited_2() -> ControlFlow { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: either add some descriptive message or remove the attribute + +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/drop_non_drop.rs b/src/tools/clippy/tests/ui/drop_non_drop.rs index 0345e8670ab83..e6433de5163d8 100644 --- a/src/tools/clippy/tests/ui/drop_non_drop.rs +++ b/src/tools/clippy/tests/ui/drop_non_drop.rs @@ -6,6 +6,11 @@ fn make_result(t: T) -> Result { Ok(t) } +// The return type should behave as `T` as the `Err` variant is uninhabited +fn make_result_uninhabited_err(t: T) -> Result { + Ok(t) +} + #[must_use] fn must_use(t: T) -> T { t @@ -41,4 +46,8 @@ fn main() { // Don't lint drop(Baz(Bar)); + + // Lint + drop(make_result_uninhabited_err(Foo)); + //~^ drop_non_drop } diff --git a/src/tools/clippy/tests/ui/drop_non_drop.stderr b/src/tools/clippy/tests/ui/drop_non_drop.stderr index b431c62c92c57..567a820990c60 100644 --- a/src/tools/clippy/tests/ui/drop_non_drop.stderr +++ b/src/tools/clippy/tests/ui/drop_non_drop.stderr @@ -1,11 +1,11 @@ error: call to `std::mem::drop` with a value that does not implement `Drop`. Dropping such a type only extends its contained lifetimes - --> tests/ui/drop_non_drop.rs:22:5 + --> tests/ui/drop_non_drop.rs:27:5 | LL | drop(Foo); | ^^^^^^^^^ | note: argument has type `main::Foo` - --> tests/ui/drop_non_drop.rs:22:10 + --> tests/ui/drop_non_drop.rs:27:10 | LL | drop(Foo); | ^^^ @@ -13,16 +13,28 @@ LL | drop(Foo); = help: to override `-D warnings` add `#[allow(clippy::drop_non_drop)]` error: call to `std::mem::drop` with a value that does not implement `Drop`. Dropping such a type only extends its contained lifetimes - --> tests/ui/drop_non_drop.rs:39:5 + --> tests/ui/drop_non_drop.rs:44:5 | LL | drop(Baz(Foo)); | ^^^^^^^^^^^^^^ | note: argument has type `main::Baz` - --> tests/ui/drop_non_drop.rs:39:10 + --> tests/ui/drop_non_drop.rs:44:10 | LL | drop(Baz(Foo)); | ^^^^^^^^ -error: aborting due to 2 previous errors +error: call to `std::mem::drop` with a value that does not implement `Drop`. Dropping such a type only extends its contained lifetimes + --> tests/ui/drop_non_drop.rs:51:5 + | +LL | drop(make_result_uninhabited_err(Foo)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: argument has type `std::result::Result` + --> tests/ui/drop_non_drop.rs:51:10 + | +LL | drop(make_result_uninhabited_err(Foo)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/duplicate_underscore_argument.rs b/src/tools/clippy/tests/ui/duplicate_underscore_argument.rs index b71f5a20a8439..820930bc6c12c 100644 --- a/src/tools/clippy/tests/ui/duplicate_underscore_argument.rs +++ b/src/tools/clippy/tests/ui/duplicate_underscore_argument.rs @@ -5,7 +5,4 @@ fn join_the_dark_side(darth: i32, _darth: i32) {} fn join_the_light_side(knight: i32, _master: i32) {} // the Force is strong with this one -fn main() { - join_the_dark_side(0, 0); - join_the_light_side(0, 0); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/duration_suboptimal_units.fixed b/src/tools/clippy/tests/ui/duration_suboptimal_units.fixed index 515ec10e572b1..a4eb981ebfa21 100644 --- a/src/tools/clippy/tests/ui/duration_suboptimal_units.fixed +++ b/src/tools/clippy/tests/ui/duration_suboptimal_units.fixed @@ -94,3 +94,14 @@ fn issue16457() { // Methods taking something else than `u64` are not covered _ = Duration::from_nanos_u128(1 << 90); } + +#[clippy::msrv = "1.90"] +fn insufficient_msrv() { + _ = Duration::from_secs(67_768_040_922_076_800); +} + +#[clippy::msrv = "1.91"] +fn sufficient_msrv() { + _ = Duration::from_hours(18824455811688); + //~^ duration_suboptimal_units +} diff --git a/src/tools/clippy/tests/ui/duration_suboptimal_units.rs b/src/tools/clippy/tests/ui/duration_suboptimal_units.rs index 357c52cffb35a..e31ca679b5a1a 100644 --- a/src/tools/clippy/tests/ui/duration_suboptimal_units.rs +++ b/src/tools/clippy/tests/ui/duration_suboptimal_units.rs @@ -94,3 +94,14 @@ fn issue16457() { // Methods taking something else than `u64` are not covered _ = Duration::from_nanos_u128(1 << 90); } + +#[clippy::msrv = "1.90"] +fn insufficient_msrv() { + _ = Duration::from_secs(67_768_040_922_076_800); +} + +#[clippy::msrv = "1.91"] +fn sufficient_msrv() { + _ = Duration::from_secs(67_768_040_922_076_800); + //~^ duration_suboptimal_units +} diff --git a/src/tools/clippy/tests/ui/duration_suboptimal_units.stderr b/src/tools/clippy/tests/ui/duration_suboptimal_units.stderr index f129dbade8dc1..97b26f6667eb8 100644 --- a/src/tools/clippy/tests/ui/duration_suboptimal_units.stderr +++ b/src/tools/clippy/tests/ui/duration_suboptimal_units.stderr @@ -148,5 +148,17 @@ LL - Duration::from_secs(300) LL + Duration::from_mins(5) | -error: aborting due to 12 previous errors +error: constructing a `Duration` using a smaller unit when a larger unit would be more readable + --> tests/ui/duration_suboptimal_units.rs:105:9 + | +LL | _ = Duration::from_secs(67_768_040_922_076_800); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try using from_hours + | +LL - _ = Duration::from_secs(67_768_040_922_076_800); +LL + _ = Duration::from_hours(18824455811688); + | + +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/erasing_op.rs b/src/tools/clippy/tests/ui/erasing_op.rs index 9237b9eb11f05..8867f445edcb4 100644 --- a/src/tools/clippy/tests/ui/erasing_op.rs +++ b/src/tools/clippy/tests/ui/erasing_op.rs @@ -49,6 +49,4 @@ fn test(x: u8) { //~^ erasing_op } -fn main() { - test(0) -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed index 107318e5323d0..fdaf1c37b2018 100644 --- a/src/tools/clippy/tests/ui/eta.fixed +++ b/src/tools/clippy/tests/ui/eta.fixed @@ -643,3 +643,12 @@ where { maybe.map(|x| visitor(x)); } + +trait Issue16360: Sized { + fn method(&self); + + fn ice_machine(array: [Self; 1]) { + array.iter().for_each(Self::method); + //~^ redundant_closure_for_method_calls + } +} diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs index b85e8e75153a1..1054060db4494 100644 --- a/src/tools/clippy/tests/ui/eta.rs +++ b/src/tools/clippy/tests/ui/eta.rs @@ -643,3 +643,12 @@ where { maybe.map(|x| visitor(x)); } + +trait Issue16360: Sized { + fn method(&self); + + fn ice_machine(array: [Self; 1]) { + array.iter().for_each(|item| item.method()); + //~^ redundant_closure_for_method_calls + } +} diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr index 0b401cdea9875..2e0ccc557915a 100644 --- a/src/tools/clippy/tests/ui/eta.stderr +++ b/src/tools/clippy/tests/ui/eta.stderr @@ -256,5 +256,11 @@ error: redundant closure LL | .map(|n| f(n)) | ^^^^^^^^ help: replace the closure with the function itself: `f` -error: aborting due to 42 previous errors +error: redundant closure + --> tests/ui/eta.rs:651:31 + | +LL | array.iter().for_each(|item| item.method()); + | ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `Self::method` + +error: aborting due to 43 previous errors diff --git a/src/tools/clippy/tests/ui/expect.rs b/src/tools/clippy/tests/ui/expect.rs index 1ab01ecfcfe3a..75b7916ecc5b7 100644 --- a/src/tools/clippy/tests/ui/expect.rs +++ b/src/tools/clippy/tests/ui/expect.rs @@ -34,8 +34,4 @@ fn issue_15247() { //~^ expect_used } -fn main() { - expect_option(); - expect_result(); - issue_15247(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/explicit_counter_loop.rs b/src/tools/clippy/tests/ui/explicit_counter_loop.rs index ec4cecf377667..ebb261a0d97a7 100644 --- a/src/tools/clippy/tests/ui/explicit_counter_loop.rs +++ b/src/tools/clippy/tests/ui/explicit_counter_loop.rs @@ -33,10 +33,10 @@ fn main() { } let vec = [1, 2, 3, 4]; - // Potential false positives let mut _index = 0; _index = 1; for _v in &vec { + //~^ explicit_counter_loop _index += 1 } @@ -299,3 +299,21 @@ mod issue_13123 { } } } + +fn issue16612(v: Vec, s: i64) { + use std::hint::black_box; + + let mut i = 1; + for item in &v { + //~^ explicit_counter_loop + black_box((i, *item)); + i += 1; + } + + let mut j = s + 1; + for item in &v { + //~^ explicit_counter_loop + black_box((j, *item)); + j += 1; + } +} diff --git a/src/tools/clippy/tests/ui/explicit_counter_loop.stderr b/src/tools/clippy/tests/ui/explicit_counter_loop.stderr index a73516558c20c..7a83df05ec0a8 100644 --- a/src/tools/clippy/tests/ui/explicit_counter_loop.stderr +++ b/src/tools/clippy/tests/ui/explicit_counter_loop.stderr @@ -25,6 +25,12 @@ error: the variable `_index` is used as a loop counter LL | for _v in vec { | ^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.into_iter().enumerate()` +error: the variable `_index` is used as a loop counter + --> tests/ui/explicit_counter_loop.rs:38:5 + | +LL | for _v in &vec { + | ^^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in (1..).zip(vec.iter())` + error: the variable `count` is used as a loop counter --> tests/ui/explicit_counter_loop.rs:118:9 | @@ -63,5 +69,17 @@ error: the variable `_index` is used as a loop counter LL | 'label: for v in vec { | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `'label: for (_index, v) in vec.into_iter().enumerate()` -error: aborting due to 10 previous errors +error: the variable `i` is used as a loop counter + --> tests/ui/explicit_counter_loop.rs:307:5 + | +LL | for item in &v { + | ^^^^^^^^^^^^^^ help: consider using: `for (i, item) in (1..).zip(v.iter())` + +error: the variable `j` is used as a loop counter + --> tests/ui/explicit_counter_loop.rs:314:5 + | +LL | for item in &v { + | ^^^^^^^^^^^^^^ help: consider using: `for (j, item) in (s + 1..).zip(v.iter())` + +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/floating_point_abs.fixed b/src/tools/clippy/tests/ui/floating_point_abs.fixed index e8d64a3d7c296..53e9014e284f5 100644 --- a/src/tools/clippy/tests/ui/floating_point_abs.fixed +++ b/src/tools/clippy/tests/ui/floating_point_abs.fixed @@ -73,18 +73,4 @@ fn not_fake_abs5(a: A) -> f64 { if a.a > 0.0 { a.a } else { -a.b } } -fn main() { - fake_abs1(5.0); - fake_abs2(5.0); - fake_abs3(A { a: 5.0, b: 5.0 }); - fake_abs4(5.0); - fake_abs5(A { a: 5.0, b: 5.0 }); - fake_nabs1(5.0); - fake_nabs2(5.0); - fake_nabs3(A { a: 5.0, b: 5.0 }); - not_fake_abs1(5.0); - not_fake_abs2(5.0); - not_fake_abs3(5.0, 5.0); - not_fake_abs4(A { a: 5.0, b: 5.0 }); - not_fake_abs5(A { a: 5.0, b: 5.0 }); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/floating_point_abs.rs b/src/tools/clippy/tests/ui/floating_point_abs.rs index a27279b0662f5..d5c792f6eb9c9 100644 --- a/src/tools/clippy/tests/ui/floating_point_abs.rs +++ b/src/tools/clippy/tests/ui/floating_point_abs.rs @@ -73,18 +73,4 @@ fn not_fake_abs5(a: A) -> f64 { if a.a > 0.0 { a.a } else { -a.b } } -fn main() { - fake_abs1(5.0); - fake_abs2(5.0); - fake_abs3(A { a: 5.0, b: 5.0 }); - fake_abs4(5.0); - fake_abs5(A { a: 5.0, b: 5.0 }); - fake_nabs1(5.0); - fake_nabs2(5.0); - fake_nabs3(A { a: 5.0, b: 5.0 }); - not_fake_abs1(5.0); - not_fake_abs2(5.0); - not_fake_abs3(5.0, 5.0); - not_fake_abs4(A { a: 5.0, b: 5.0 }); - not_fake_abs5(A { a: 5.0, b: 5.0 }); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/four_forward_slashes_bare_cr.rs b/src/tools/clippy/tests/ui/four_forward_slashes_bare_cr.rs index 19123cd206e37..9f3388512a059 100644 --- a/src/tools/clippy/tests/ui/four_forward_slashes_bare_cr.rs +++ b/src/tools/clippy/tests/ui/four_forward_slashes_bare_cr.rs @@ -1,4 +1,3 @@ -//@no-rustfix #![warn(clippy::four_forward_slashes)] //~v four_forward_slashes diff --git a/src/tools/clippy/tests/ui/four_forward_slashes_bare_cr.stderr b/src/tools/clippy/tests/ui/four_forward_slashes_bare_cr.stderr index 64e70b97db9ad..266a5fa72c54a 100644 --- a/src/tools/clippy/tests/ui/four_forward_slashes_bare_cr.stderr +++ b/src/tools/clippy/tests/ui/four_forward_slashes_bare_cr.stderr @@ -1,5 +1,5 @@ error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't - --> tests/ui/four_forward_slashes_bare_cr.rs:5:1 + --> tests/ui/four_forward_slashes_bare_cr.rs:4:1 | LL | / //// nondoc comment with bare CR: '␍' LL | | fn main() {} diff --git a/src/tools/clippy/tests/ui/infinite_iter.rs b/src/tools/clippy/tests/ui/infinite_iter.rs index 4e1668ed04fb7..f09b2a4b75918 100644 --- a/src/tools/clippy/tests/ui/infinite_iter.rs +++ b/src/tools/clippy/tests/ui/infinite_iter.rs @@ -87,10 +87,7 @@ fn potential_infinite_iters() { repeat(42).take_while(|x| *x == 42).next(); } -fn main() { - infinite_iters(); - potential_infinite_iters(); -} +fn main() {} mod finite_collect { use std::collections::HashSet; diff --git a/src/tools/clippy/tests/ui/infinite_iter.stderr b/src/tools/clippy/tests/ui/infinite_iter.stderr index 3db97313b621d..3017940c82cb1 100644 --- a/src/tools/clippy/tests/ui/infinite_iter.stderr +++ b/src/tools/clippy/tests/ui/infinite_iter.stderr @@ -100,7 +100,7 @@ LL | (0..).all(|x| x == 24); | ^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> tests/ui/infinite_iter.rs:107:31 + --> tests/ui/infinite_iter.rs:104:31 | LL | let _: HashSet = (0..).collect(); | ^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/ip_constant_from_external.rs b/src/tools/clippy/tests/ui/ip_constant_from_external.rs index 7fd27022f1274..dae15623018a3 100644 --- a/src/tools/clippy/tests/ui/ip_constant_from_external.rs +++ b/src/tools/clippy/tests/ui/ip_constant_from_external.rs @@ -7,6 +7,4 @@ fn external_constant_test() { // lint in external file `localhost.txt` } -fn main() { - external_constant_test(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/iter_kv_map.fixed b/src/tools/clippy/tests/ui/iter_kv_map.fixed index 189d76bc94319..e3ab5fd1e9eff 100644 --- a/src/tools/clippy/tests/ui/iter_kv_map.fixed +++ b/src/tools/clippy/tests/ui/iter_kv_map.fixed @@ -1,5 +1,11 @@ #![warn(clippy::iter_kv_map)] -#![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)] +#![allow( + unused_mut, + clippy::redundant_clone, + clippy::redundant_closure, + clippy::suspicious_map, + clippy::map_identity +)] use std::collections::{BTreeMap, HashMap}; @@ -195,3 +201,33 @@ fn issue16340() { let _ = hm.keys().map(|key| vec![key]); //~^ iter_kv_map } + +fn issue16515() { + let hash_map: HashMap = HashMap::new(); + hash_map.keys().flat_map(|k| Some(*k)); + //~^ iter_kv_map + + hash_map.values().flat_map(|v| Some(*v)); + //~^ iter_kv_map + + hash_map.keys().filter_map(|k| (k > &0).then_some(1)); + //~^ iter_kv_map + + hash_map.values().filter_map(|v| (v > &0).then_some(1)); + //~^ iter_kv_map + + hash_map.into_keys().flat_map(|k| Some(k)); + //~^ iter_kv_map + + let hash_map: HashMap = HashMap::new(); + hash_map.into_values().flat_map(|v| Some(v)); + //~^ iter_kv_map + + let hash_map: HashMap = HashMap::new(); + hash_map.into_keys().filter_map(|k| (k > 0).then_some(1)); + //~^ iter_kv_map + + let hash_map: HashMap = HashMap::new(); + hash_map.into_values().filter_map(|v| (v > 0).then_some(1)); + //~^ iter_kv_map +} diff --git a/src/tools/clippy/tests/ui/iter_kv_map.rs b/src/tools/clippy/tests/ui/iter_kv_map.rs index cfc3034470047..903813b1bf628 100644 --- a/src/tools/clippy/tests/ui/iter_kv_map.rs +++ b/src/tools/clippy/tests/ui/iter_kv_map.rs @@ -1,5 +1,11 @@ #![warn(clippy::iter_kv_map)] -#![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)] +#![allow( + unused_mut, + clippy::redundant_clone, + clippy::redundant_closure, + clippy::suspicious_map, + clippy::map_identity +)] use std::collections::{BTreeMap, HashMap}; @@ -199,3 +205,33 @@ fn issue16340() { let _ = hm.iter().map(|(key, _)| vec![key]); //~^ iter_kv_map } + +fn issue16515() { + let hash_map: HashMap = HashMap::new(); + hash_map.iter().flat_map(|(k, _)| Some(*k)); + //~^ iter_kv_map + + hash_map.iter().flat_map(|(_, v)| Some(*v)); + //~^ iter_kv_map + + hash_map.iter().filter_map(|(k, _)| (k > &0).then_some(1)); + //~^ iter_kv_map + + hash_map.iter().filter_map(|(_, v)| (v > &0).then_some(1)); + //~^ iter_kv_map + + hash_map.into_iter().flat_map(|(k, _)| Some(k)); + //~^ iter_kv_map + + let hash_map: HashMap = HashMap::new(); + hash_map.into_iter().flat_map(|(_, v)| Some(v)); + //~^ iter_kv_map + + let hash_map: HashMap = HashMap::new(); + hash_map.into_iter().filter_map(|(k, _)| (k > 0).then_some(1)); + //~^ iter_kv_map + + let hash_map: HashMap = HashMap::new(); + hash_map.into_iter().filter_map(|(_, v)| (v > 0).then_some(1)); + //~^ iter_kv_map +} diff --git a/src/tools/clippy/tests/ui/iter_kv_map.stderr b/src/tools/clippy/tests/ui/iter_kv_map.stderr index 866e69ea1922e..cdfd05fdd09ee 100644 --- a/src/tools/clippy/tests/ui/iter_kv_map.stderr +++ b/src/tools/clippy/tests/ui/iter_kv_map.stderr @@ -1,5 +1,5 @@ error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:14:13 + --> tests/ui/iter_kv_map.rs:20:13 | LL | let _ = map.iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` @@ -8,73 +8,73 @@ LL | let _ = map.iter().map(|(key, _)| key).collect::>(); = help: to override `-D warnings` add `#[allow(clippy::iter_kv_map)]` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:16:13 + --> tests/ui/iter_kv_map.rs:22:13 | LL | let _ = map.iter().map(|(_, value)| value).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:18:13 + --> tests/ui/iter_kv_map.rs:24:13 | LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:21:13 + --> tests/ui/iter_kv_map.rs:27:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:23:13 + --> tests/ui/iter_kv_map.rs:29:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:26:13 + --> tests/ui/iter_kv_map.rs:32:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:28:13 + --> tests/ui/iter_kv_map.rs:34:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:31:13 + --> tests/ui/iter_kv_map.rs:37:13 | LL | let _ = map.clone().iter().map(|(_, val)| val).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:33:13 + --> tests/ui/iter_kv_map.rs:39:13 | LL | let _ = map.iter().map(|(key, _)| key).filter(|x| x.is_multiple_of(2)).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:48:13 + --> tests/ui/iter_kv_map.rs:54:13 | LL | let _ = map.iter().map(|(key, _value)| key * 9).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:50:13 + --> tests/ui/iter_kv_map.rs:56:13 | LL | let _ = map.iter().map(|(_key, value)| value * 17).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:54:13 + --> tests/ui/iter_kv_map.rs:60:13 | LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:58:13 + --> tests/ui/iter_kv_map.rs:64:13 | LL | let _ = map | _____________^ @@ -97,85 +97,85 @@ LL + }) | error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:69:13 + --> tests/ui/iter_kv_map.rs:75:13 | LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:74:13 + --> tests/ui/iter_kv_map.rs:80:13 | LL | let _ = map.iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:76:13 + --> tests/ui/iter_kv_map.rs:82:13 | LL | let _ = map.iter().map(|(_, value)| value).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:78:13 + --> tests/ui/iter_kv_map.rs:84:13 | LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:81:13 + --> tests/ui/iter_kv_map.rs:87:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:83:13 + --> tests/ui/iter_kv_map.rs:89:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:86:13 + --> tests/ui/iter_kv_map.rs:92:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:88:13 + --> tests/ui/iter_kv_map.rs:94:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:91:13 + --> tests/ui/iter_kv_map.rs:97:13 | LL | let _ = map.clone().iter().map(|(_, val)| val).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:93:13 + --> tests/ui/iter_kv_map.rs:99:13 | LL | let _ = map.iter().map(|(key, _)| key).filter(|x| x.is_multiple_of(2)).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:108:13 + --> tests/ui/iter_kv_map.rs:114:13 | LL | let _ = map.iter().map(|(key, _value)| key * 9).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:110:13 + --> tests/ui/iter_kv_map.rs:116:13 | LL | let _ = map.iter().map(|(_key, value)| value * 17).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:114:13 + --> tests/ui/iter_kv_map.rs:120:13 | LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:118:13 + --> tests/ui/iter_kv_map.rs:124:13 | LL | let _ = map | _____________^ @@ -198,82 +198,130 @@ LL + }) | error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:129:13 + --> tests/ui/iter_kv_map.rs:135:13 | LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:145:13 + --> tests/ui/iter_kv_map.rs:151:13 | LL | let _ = map.iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:148:13 + --> tests/ui/iter_kv_map.rs:154:13 | LL | let _ = map.iter().map(|(_, value)| value).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:151:13 + --> tests/ui/iter_kv_map.rs:157:13 | LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:160:13 + --> tests/ui/iter_kv_map.rs:166:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:163:13 + --> tests/ui/iter_kv_map.rs:169:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:166:13 + --> tests/ui/iter_kv_map.rs:172:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:169:13 + --> tests/ui/iter_kv_map.rs:175:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:172:13 + --> tests/ui/iter_kv_map.rs:178:13 | LL | let _ = map.iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:175:13 + --> tests/ui/iter_kv_map.rs:181:13 | LL | let _ = map.iter().map(|(_, value)| value).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:178:13 + --> tests/ui/iter_kv_map.rs:184:13 | LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:193:13 + --> tests/ui/iter_kv_map.rs:199:13 | LL | let _ = map.as_ref().iter().map(|(_, v)| v).copied().collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.as_ref().values()` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:199:13 + --> tests/ui/iter_kv_map.rs:205:13 | LL | let _ = hm.iter().map(|(key, _)| vec![key]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hm.keys().map(|key| vec![key])` -error: aborting due to 40 previous errors +error: iterating on a map's keys + --> tests/ui/iter_kv_map.rs:211:5 + | +LL | hash_map.iter().flat_map(|(k, _)| Some(*k)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.keys().flat_map(|k| Some(*k))` + +error: iterating on a map's values + --> tests/ui/iter_kv_map.rs:214:5 + | +LL | hash_map.iter().flat_map(|(_, v)| Some(*v)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.values().flat_map(|v| Some(*v))` + +error: iterating on a map's keys + --> tests/ui/iter_kv_map.rs:217:5 + | +LL | hash_map.iter().filter_map(|(k, _)| (k > &0).then_some(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.keys().filter_map(|k| (k > &0).then_some(1))` + +error: iterating on a map's values + --> tests/ui/iter_kv_map.rs:220:5 + | +LL | hash_map.iter().filter_map(|(_, v)| (v > &0).then_some(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.values().filter_map(|v| (v > &0).then_some(1))` + +error: iterating on a map's keys + --> tests/ui/iter_kv_map.rs:223:5 + | +LL | hash_map.into_iter().flat_map(|(k, _)| Some(k)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.into_keys().flat_map(|k| Some(k))` + +error: iterating on a map's values + --> tests/ui/iter_kv_map.rs:227:5 + | +LL | hash_map.into_iter().flat_map(|(_, v)| Some(v)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.into_values().flat_map(|v| Some(v))` + +error: iterating on a map's keys + --> tests/ui/iter_kv_map.rs:231:5 + | +LL | hash_map.into_iter().filter_map(|(k, _)| (k > 0).then_some(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.into_keys().filter_map(|k| (k > 0).then_some(1))` + +error: iterating on a map's values + --> tests/ui/iter_kv_map.rs:235:5 + | +LL | hash_map.into_iter().filter_map(|(_, v)| (v > 0).then_some(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.into_values().filter_map(|v| (v > 0).then_some(1))` + +error: aborting due to 48 previous errors diff --git a/src/tools/clippy/tests/ui/iter_on_empty_collections.fixed b/src/tools/clippy/tests/ui/iter_on_empty_collections.fixed index 0c2100034e184..f4c2bc43a6793 100644 --- a/src/tools/clippy/tests/ui/iter_on_empty_collections.fixed +++ b/src/tools/clippy/tests/ui/iter_on_empty_collections.fixed @@ -84,8 +84,4 @@ mod custom_option { } } -fn main() { - array(); - custom_option::custom_option(); - in_macros!(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/iter_on_empty_collections.rs b/src/tools/clippy/tests/ui/iter_on_empty_collections.rs index 0fb7a32d3691f..f5852d97c93c8 100644 --- a/src/tools/clippy/tests/ui/iter_on_empty_collections.rs +++ b/src/tools/clippy/tests/ui/iter_on_empty_collections.rs @@ -84,8 +84,4 @@ mod custom_option { } } -fn main() { - array(); - custom_option::custom_option(); - in_macros!(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/iter_on_single_items.fixed b/src/tools/clippy/tests/ui/iter_on_single_items.fixed index 044037aac2e34..c5f85122aa76c 100644 --- a/src/tools/clippy/tests/ui/iter_on_single_items.fixed +++ b/src/tools/clippy/tests/ui/iter_on_single_items.fixed @@ -61,11 +61,7 @@ mod custom_option { } } -fn main() { - array(); - custom_option::custom_option(); - in_macros!(); -} +fn main() {} mod issue14981 { use std::option::IntoIter; diff --git a/src/tools/clippy/tests/ui/iter_on_single_items.rs b/src/tools/clippy/tests/ui/iter_on_single_items.rs index c925d0e480fac..ffeb76d627b0b 100644 --- a/src/tools/clippy/tests/ui/iter_on_single_items.rs +++ b/src/tools/clippy/tests/ui/iter_on_single_items.rs @@ -61,11 +61,7 @@ mod custom_option { } } -fn main() { - array(); - custom_option::custom_option(); - in_macros!(); -} +fn main() {} mod issue14981 { use std::option::IntoIter; diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed index 4171f19469a4d..520b4f8be8cff 100644 --- a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed +++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed @@ -102,3 +102,63 @@ fn main() { fn cloned_flatten(x: Option<&Option>) -> Option { x.cloned().flatten() } + +mod issue_16428 { + #[derive(Clone)] + struct Foo; + + impl Foo { + async fn do_async(&self) {} + } + + fn async_move_map() -> Vec> { + let map: std::collections::HashMap<(), Foo> = std::collections::HashMap::new(); + + // Should NOT lint: async move block captures `item` by value + map.values() + .cloned() + .map(|item| async move { item.do_async().await }) + .collect::>() + } + + fn async_move_for_each() { + let map: std::collections::HashMap<(), Foo> = std::collections::HashMap::new(); + + // Should NOT lint: async move block captures `item` by value + map.values() + .cloned() + .for_each(|item| drop(async move { item.do_async().await })); + } + + fn move_closure() { + let vec = vec!["1".to_string(), "2".to_string()]; + + // Should NOT lint: move closure captures `x` by value + let _: Vec<_> = vec.iter().cloned().map(|x| move || x.len()).collect(); + } + + fn async_move_not_capturing_param() { + let vec = vec!["1".to_string(), "2".to_string()]; + + // Should lint: async move captures `y`, not `x` + let _ = vec.iter().map(|x| { + //~^ redundant_iter_cloned + let y = x.len(); + async move { y } + }); + } + + fn move_closure_not_capturing_param() { + let vec = vec!["1".to_string(), "2".to_string()]; + + // Should lint: move closure captures `y`, not `x` + let _: Vec<_> = vec + //~^ redundant_iter_cloned + .iter() + .map(|x| { + let y = x.len(); + move || y + }) + .collect(); + } +} diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs index fe6aba24dd3e2..3e79675dd7c60 100644 --- a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs +++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs @@ -103,3 +103,64 @@ fn main() { fn cloned_flatten(x: Option<&Option>) -> Option { x.cloned().flatten() } + +mod issue_16428 { + #[derive(Clone)] + struct Foo; + + impl Foo { + async fn do_async(&self) {} + } + + fn async_move_map() -> Vec> { + let map: std::collections::HashMap<(), Foo> = std::collections::HashMap::new(); + + // Should NOT lint: async move block captures `item` by value + map.values() + .cloned() + .map(|item| async move { item.do_async().await }) + .collect::>() + } + + fn async_move_for_each() { + let map: std::collections::HashMap<(), Foo> = std::collections::HashMap::new(); + + // Should NOT lint: async move block captures `item` by value + map.values() + .cloned() + .for_each(|item| drop(async move { item.do_async().await })); + } + + fn move_closure() { + let vec = vec!["1".to_string(), "2".to_string()]; + + // Should NOT lint: move closure captures `x` by value + let _: Vec<_> = vec.iter().cloned().map(|x| move || x.len()).collect(); + } + + fn async_move_not_capturing_param() { + let vec = vec!["1".to_string(), "2".to_string()]; + + // Should lint: async move captures `y`, not `x` + let _ = vec.iter().cloned().map(|x| { + //~^ redundant_iter_cloned + let y = x.len(); + async move { y } + }); + } + + fn move_closure_not_capturing_param() { + let vec = vec!["1".to_string(), "2".to_string()]; + + // Should lint: move closure captures `y`, not `x` + let _: Vec<_> = vec + //~^ redundant_iter_cloned + .iter() + .cloned() + .map(|x| { + let y = x.len(); + move || y + }) + .collect(); + } +} diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr index f234d19e4aaaa..72b00ca2e32cf 100644 --- a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr +++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr @@ -165,5 +165,47 @@ LL | let _ = vec.iter().cloned().any(|x| x.len() == 1); | | | help: try: `.any(|x| x.len() == 1)` -error: aborting due to 19 previous errors +error: unneeded cloning of iterator items + --> tests/ui/iter_overeager_cloned.rs:145:17 + | +LL | let _ = vec.iter().cloned().map(|x| { + | _________________^ +LL | | +LL | | let y = x.len(); +LL | | async move { y } +LL | | }); + | |__________^ + | +help: try + | +LL ~ let _ = vec.iter().map(|x| { +LL + +LL + let y = x.len(); +LL + async move { y } +LL ~ }); + | + +error: unneeded cloning of iterator items + --> tests/ui/iter_overeager_cloned.rs:156:25 + | +LL | let _: Vec<_> = vec + | _________________________^ +LL | | +LL | | .iter() +LL | | .cloned() +... | +LL | | move || y +LL | | }) + | |______________^ + | +help: try + | +LL ~ .iter() +LL + .map(|x| { +LL + let y = x.len(); +LL + move || y +LL + }) + | + +error: aborting due to 21 previous errors diff --git a/src/tools/clippy/tests/ui/iter_with_drain.fixed b/src/tools/clippy/tests/ui/iter_with_drain.fixed index b0661ffb981b1..9e0a03f580c0b 100644 --- a/src/tools/clippy/tests/ui/iter_with_drain.fixed +++ b/src/tools/clippy/tests/ui/iter_with_drain.fixed @@ -62,9 +62,4 @@ fn should_not_help_0(bomb: &mut Bomb) { let _: Vec = bomb.fire.drain(..).collect(); } -fn main() { - full(); - closed(); - should_not_help(); - should_not_help_0(&mut Bomb::default()); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/iter_with_drain.rs b/src/tools/clippy/tests/ui/iter_with_drain.rs index 746b0f9a5eda3..6546c93071af3 100644 --- a/src/tools/clippy/tests/ui/iter_with_drain.rs +++ b/src/tools/clippy/tests/ui/iter_with_drain.rs @@ -62,9 +62,4 @@ fn should_not_help_0(bomb: &mut Bomb) { let _: Vec = bomb.fire.drain(..).collect(); } -fn main() { - full(); - closed(); - should_not_help(); - should_not_help_0(&mut Bomb::default()); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/join_absolute_paths.1.fixed b/src/tools/clippy/tests/ui/join_absolute_paths.1.fixed new file mode 100644 index 0000000000000..ff524b529b187 --- /dev/null +++ b/src/tools/clippy/tests/ui/join_absolute_paths.1.fixed @@ -0,0 +1,36 @@ +#![allow(clippy::needless_raw_string_hashes)] +#![warn(clippy::join_absolute_paths)] + +use std::path::{Path, PathBuf}; + +fn main() { + let path = Path::new("/bin"); + path.join("sh"); + //~^ join_absolute_paths + + let path = PathBuf::from("/bin"); + path.join("sh"); + //~^ join_absolute_paths + + let path = PathBuf::from("/bin"); + path.join(r#"sh"#); + //~^ join_absolute_paths + + let path = Path::new("C:\\Users"); + path.join("user"); + //~^ join_absolute_paths + + let path = PathBuf::from("C:\\Users"); + path.join("user"); + //~^ join_absolute_paths + + let path = PathBuf::from("C:\\Users"); + path.join(r#"user"#); + //~^ join_absolute_paths + + let path: &[&str] = &["/bin"]; + path.join("/sh"); + + let path = Path::new("/bin"); + path.join("sh"); +} diff --git a/src/tools/clippy/tests/ui/join_absolute_paths.2.fixed b/src/tools/clippy/tests/ui/join_absolute_paths.2.fixed new file mode 100644 index 0000000000000..372647ecde646 --- /dev/null +++ b/src/tools/clippy/tests/ui/join_absolute_paths.2.fixed @@ -0,0 +1,36 @@ +#![allow(clippy::needless_raw_string_hashes)] +#![warn(clippy::join_absolute_paths)] + +use std::path::{Path, PathBuf}; + +fn main() { + let path = Path::new("/bin"); + PathBuf::from("/sh"); + //~^ join_absolute_paths + + let path = PathBuf::from("/bin"); + PathBuf::from("/sh"); + //~^ join_absolute_paths + + let path = PathBuf::from("/bin"); + PathBuf::from(r#"/sh"#); + //~^ join_absolute_paths + + let path = Path::new("C:\\Users"); + PathBuf::from("\\user"); + //~^ join_absolute_paths + + let path = PathBuf::from("C:\\Users"); + PathBuf::from("\\user"); + //~^ join_absolute_paths + + let path = PathBuf::from("C:\\Users"); + PathBuf::from(r#"\user"#); + //~^ join_absolute_paths + + let path: &[&str] = &["/bin"]; + path.join("/sh"); + + let path = Path::new("/bin"); + path.join("sh"); +} diff --git a/src/tools/clippy/tests/ui/join_absolute_paths.rs b/src/tools/clippy/tests/ui/join_absolute_paths.rs index 144c9147c2a1b..dffc4a5f10ed2 100644 --- a/src/tools/clippy/tests/ui/join_absolute_paths.rs +++ b/src/tools/clippy/tests/ui/join_absolute_paths.rs @@ -1,5 +1,3 @@ -//@no-rustfix - #![allow(clippy::needless_raw_string_hashes)] #![warn(clippy::join_absolute_paths)] @@ -10,10 +8,6 @@ fn main() { path.join("/sh"); //~^ join_absolute_paths - let path = Path::new("C:\\Users"); - path.join("\\user"); - //~^ join_absolute_paths - let path = PathBuf::from("/bin"); path.join("/sh"); //~^ join_absolute_paths @@ -22,6 +16,18 @@ fn main() { path.join(r#"/sh"#); //~^ join_absolute_paths + let path = Path::new("C:\\Users"); + path.join("\\user"); + //~^ join_absolute_paths + + let path = PathBuf::from("C:\\Users"); + path.join("\\user"); + //~^ join_absolute_paths + + let path = PathBuf::from("C:\\Users"); + path.join(r#"\user"#); + //~^ join_absolute_paths + let path: &[&str] = &["/bin"]; path.join("/sh"); diff --git a/src/tools/clippy/tests/ui/join_absolute_paths.stderr b/src/tools/clippy/tests/ui/join_absolute_paths.stderr index 300946bf3b5fc..c44292276d277 100644 --- a/src/tools/clippy/tests/ui/join_absolute_paths.stderr +++ b/src/tools/clippy/tests/ui/join_absolute_paths.stderr @@ -1,5 +1,5 @@ error: argument to `Path::join` starts with a path separator - --> tests/ui/join_absolute_paths.rs:10:15 + --> tests/ui/join_absolute_paths.rs:8:15 | LL | path.join("/sh"); | ^^^^^ @@ -19,7 +19,43 @@ LL + PathBuf::from("/sh"); | error: argument to `Path::join` starts with a path separator - --> tests/ui/join_absolute_paths.rs:14:15 + --> tests/ui/join_absolute_paths.rs:12:15 + | +LL | path.join("/sh"); + | ^^^^^ + | + = note: joining a path starting with separator will replace the path instead +help: if this is unintentional, try removing the starting separator + | +LL - path.join("/sh"); +LL + path.join("sh"); + | +help: if this is intentional, consider using `Path::new` + | +LL - path.join("/sh"); +LL + PathBuf::from("/sh"); + | + +error: argument to `Path::join` starts with a path separator + --> tests/ui/join_absolute_paths.rs:16:15 + | +LL | path.join(r#"/sh"#); + | ^^^^^^^^ + | + = note: joining a path starting with separator will replace the path instead +help: if this is unintentional, try removing the starting separator + | +LL - path.join(r#"/sh"#); +LL + path.join(r#"sh"#); + | +help: if this is intentional, consider using `Path::new` + | +LL - path.join(r#"/sh"#); +LL + PathBuf::from(r#"/sh"#); + | + +error: argument to `Path::join` starts with a path separator + --> tests/ui/join_absolute_paths.rs:20:15 | LL | path.join("\\user"); | ^^^^^^^^ @@ -28,7 +64,7 @@ LL | path.join("\\user"); help: if this is unintentional, try removing the starting separator | LL - path.join("\\user"); -LL + path.join("\user"); +LL + path.join("user"); | help: if this is intentional, consider using `Path::new` | @@ -37,40 +73,40 @@ LL + PathBuf::from("\\user"); | error: argument to `Path::join` starts with a path separator - --> tests/ui/join_absolute_paths.rs:18:15 + --> tests/ui/join_absolute_paths.rs:24:15 | -LL | path.join("/sh"); - | ^^^^^ +LL | path.join("\\user"); + | ^^^^^^^^ | = note: joining a path starting with separator will replace the path instead help: if this is unintentional, try removing the starting separator | -LL - path.join("/sh"); -LL + path.join("sh"); +LL - path.join("\\user"); +LL + path.join("user"); | help: if this is intentional, consider using `Path::new` | -LL - path.join("/sh"); -LL + PathBuf::from("/sh"); +LL - path.join("\\user"); +LL + PathBuf::from("\\user"); | error: argument to `Path::join` starts with a path separator - --> tests/ui/join_absolute_paths.rs:22:15 + --> tests/ui/join_absolute_paths.rs:28:15 | -LL | path.join(r#"/sh"#); - | ^^^^^^^^ +LL | path.join(r#"\user"#); + | ^^^^^^^^^^ | = note: joining a path starting with separator will replace the path instead help: if this is unintentional, try removing the starting separator | -LL - path.join(r#"/sh"#); -LL + path.join(r#"sh"#); +LL - path.join(r#"\user"#); +LL + path.join(r#"user"#); | help: if this is intentional, consider using `Path::new` | -LL - path.join(r#"/sh"#); -LL + PathBuf::from(r#"/sh"#); +LL - path.join(r#"\user"#); +LL + PathBuf::from(r#"\user"#); | -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/len_without_is_empty_expect.rs b/src/tools/clippy/tests/ui/len_without_is_empty_expect.rs index 9d1245e2d02ad..4c427904a82b0 100644 --- a/src/tools/clippy/tests/ui/len_without_is_empty_expect.rs +++ b/src/tools/clippy/tests/ui/len_without_is_empty_expect.rs @@ -1,4 +1,3 @@ -//@no-rustfix #![allow(clippy::len_without_is_empty)] // Check that the lint expectation is fulfilled even if the lint is allowed at the type level. diff --git a/src/tools/clippy/tests/ui/len_without_is_empty_expect.stderr b/src/tools/clippy/tests/ui/len_without_is_empty_expect.stderr index e96870f054e43..f8fecf5a69950 100644 --- a/src/tools/clippy/tests/ui/len_without_is_empty_expect.stderr +++ b/src/tools/clippy/tests/ui/len_without_is_empty_expect.stderr @@ -1,5 +1,5 @@ error: this lint expectation is unfulfilled - --> tests/ui/len_without_is_empty_expect.rs:18:14 + --> tests/ui/len_without_is_empty_expect.rs:17:14 | LL | #[expect(clippy::len_without_is_empty)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/let_if_seq.rs b/src/tools/clippy/tests/ui/let_if_seq.rs index 69d6319fa8bf2..ebd9cfe4b8d5c 100644 --- a/src/tools/clippy/tests/ui/let_if_seq.rs +++ b/src/tools/clippy/tests/ui/let_if_seq.rs @@ -69,11 +69,6 @@ fn allow_works() -> i32 { } fn main() { - early_return(); - issue975(); - issue985(); - issue985_alt(); - let mut foo = 0; //~^ useless_let_if_seq diff --git a/src/tools/clippy/tests/ui/let_if_seq.stderr b/src/tools/clippy/tests/ui/let_if_seq.stderr index b86bca6b384bc..417d9287ad9c7 100644 --- a/src/tools/clippy/tests/ui/let_if_seq.stderr +++ b/src/tools/clippy/tests/ui/let_if_seq.stderr @@ -1,5 +1,5 @@ error: `if _ { .. } else { .. }` is an expression - --> tests/ui/let_if_seq.rs:77:5 + --> tests/ui/let_if_seq.rs:72:5 | LL | / let mut foo = 0; LL | | @@ -14,7 +14,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::useless_let_if_seq)]` error: `if _ { .. } else { .. }` is an expression - --> tests/ui/let_if_seq.rs:84:5 + --> tests/ui/let_if_seq.rs:79:5 | LL | / let mut bar = 0; LL | | @@ -28,7 +28,7 @@ LL | | } = note: you might not need `mut` at all error: `if _ { .. } else { .. }` is an expression - --> tests/ui/let_if_seq.rs:94:5 + --> tests/ui/let_if_seq.rs:89:5 | LL | / let quz; LL | | @@ -40,7 +40,7 @@ LL | | } | |_____^ help: it is more idiomatic to write: `let quz = if f() { 42 } else { 0 };` error: `if _ { .. } else { .. }` is an expression - --> tests/ui/let_if_seq.rs:125:5 + --> tests/ui/let_if_seq.rs:120:5 | LL | / let mut baz = 0; LL | | @@ -53,7 +53,7 @@ LL | | } = note: you might not need `mut` at all error: `if _ { .. } else { .. }` is an expression - --> tests/ui/let_if_seq.rs:144:5 + --> tests/ui/let_if_seq.rs:139:5 | LL | / let foo; LL | | @@ -65,7 +65,7 @@ LL | | } | |_____^ help: it is more idiomatic to write: `let foo = if bar() { 42 } else { 0 };` error: `if _ { .. } else { .. }` is an expression - --> tests/ui/let_if_seq.rs:163:5 + --> tests/ui/let_if_seq.rs:158:5 | LL | / let foo; LL | | diff --git a/src/tools/clippy/tests/ui/let_underscore_future.rs b/src/tools/clippy/tests/ui/let_underscore_future.rs index 6347c792280e9..eb1a985a91172 100644 --- a/src/tools/clippy/tests/ui/let_underscore_future.rs +++ b/src/tools/clippy/tests/ui/let_underscore_future.rs @@ -1,5 +1,5 @@ use std::future::Future; -//@no-rustfix + async fn some_async_fn() {} fn sync_side_effects() {} diff --git a/src/tools/clippy/tests/ui/let_underscore_must_use.rs b/src/tools/clippy/tests/ui/let_underscore_must_use.rs index 5cf31ec63c66f..1ef43c343fb8d 100644 --- a/src/tools/clippy/tests/ui/let_underscore_must_use.rs +++ b/src/tools/clippy/tests/ui/let_underscore_must_use.rs @@ -109,4 +109,14 @@ fn main() { #[allow(clippy::let_underscore_must_use)] let _ = a; + + // No lint because this type should behave as `()` + let _ = Result::<_, std::convert::Infallible>::Ok(()); + + #[must_use] + struct T; + + // Lint because this type should behave as `T` + let _ = Result::<_, std::convert::Infallible>::Ok(T); + //~^ let_underscore_must_use } diff --git a/src/tools/clippy/tests/ui/let_underscore_must_use.stderr b/src/tools/clippy/tests/ui/let_underscore_must_use.stderr index 130ea11646fd1..23e929b5bf895 100644 --- a/src/tools/clippy/tests/ui/let_underscore_must_use.stderr +++ b/src/tools/clippy/tests/ui/let_underscore_must_use.stderr @@ -96,5 +96,13 @@ LL | let _ = a; | = help: consider explicitly using expression value -error: aborting due to 12 previous errors +error: non-binding `let` on an expression with `#[must_use]` type + --> tests/ui/let_underscore_must_use.rs:120:5 + | +LL | let _ = Result::<_, std::convert::Infallible>::Ok(T); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider explicitly using expression value + +error: aborting due to 13 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 884bef6af5f90..e0ac240edbe5e 100644 --- a/src/tools/clippy/tests/ui/manual_is_variant_and.fixed +++ b/src/tools/clippy/tests/ui/manual_is_variant_and.fixed @@ -1,5 +1,6 @@ //@aux-build:option_helpers.rs #![warn(clippy::manual_is_variant_and)] +#![allow(clippy::redundant_closure)] #[macro_use] extern crate option_helpers; @@ -112,10 +113,7 @@ fn result_methods() { let _ = opt_map!(res2, |x| x == 'a').unwrap_or_default(); // should not lint } -fn main() { - option_methods(); - result_methods(); -} +fn main() {} fn issue15202() { let xs = [None, Some(b'_'), Some(b'1')]; @@ -245,3 +243,19 @@ fn issue16419_msrv() { let _ = opt.is_some_and(then_fn) || opt.is_none(); } + +fn issue16518(opt: Option) { + let condition = |x: &i32| *x > 10; + + opt.as_ref().is_some_and(|x| condition(x)); + //~^ manual_is_variant_and + opt.as_ref().is_none_or(|x| !condition(x)); + //~^ manual_is_variant_and +} + +#[clippy::msrv = "1.75.0"] +fn issue16518_msrv(opt: Option) { + let condition = |x: &i32| *x > 10; + + opt.filter(|x| condition(x)).is_none(); +} 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 53aca94ea3708..98069cab4557e 100644 --- a/src/tools/clippy/tests/ui/manual_is_variant_and.rs +++ b/src/tools/clippy/tests/ui/manual_is_variant_and.rs @@ -1,5 +1,6 @@ //@aux-build:option_helpers.rs #![warn(clippy::manual_is_variant_and)] +#![allow(clippy::redundant_closure)] #[macro_use] extern crate option_helpers; @@ -121,10 +122,7 @@ fn result_methods() { let _ = opt_map!(res2, |x| x == 'a').unwrap_or_default(); // should not lint } -fn main() { - option_methods(); - result_methods(); -} +fn main() {} fn issue15202() { let xs = [None, Some(b'_'), Some(b'1')]; @@ -254,3 +252,19 @@ fn issue16419_msrv() { let _ = opt.is_some_and(then_fn) || opt.is_none(); } + +fn issue16518(opt: Option) { + let condition = |x: &i32| *x > 10; + + opt.filter(|x| condition(x)).is_some(); + //~^ manual_is_variant_and + opt.filter(|x| condition(x)).is_none(); + //~^ manual_is_variant_and +} + +#[clippy::msrv = "1.75.0"] +fn issue16518_msrv(opt: Option) { + let condition = |x: &i32| *x > 10; + + opt.filter(|x| condition(x)).is_none(); +} 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 56c3b80c0aa5c..88aa3bb4eed83 100644 --- a/src/tools/clippy/tests/ui/manual_is_variant_and.stderr +++ b/src/tools/clippy/tests/ui/manual_is_variant_and.stderr @@ -1,5 +1,5 @@ error: called `map().unwrap_or_default()` on an `Option` value - --> tests/ui/manual_is_variant_and.rs:51:17 + --> tests/ui/manual_is_variant_and.rs:52:17 | LL | let _ = opt.map(|x| x > 1) | _________________^ @@ -11,7 +11,7 @@ LL | | .unwrap_or_default(); = help: to override `-D warnings` add `#[allow(clippy::manual_is_variant_and)]` error: called `map().unwrap_or_default()` on an `Option` value - --> tests/ui/manual_is_variant_and.rs:56:17 + --> tests/ui/manual_is_variant_and.rs:57:17 | LL | let _ = opt.map(|x| { | _________________^ @@ -30,13 +30,13 @@ LL ~ }); | error: called `map().unwrap_or_default()` on an `Option` value - --> tests/ui/manual_is_variant_and.rs:61:17 + --> tests/ui/manual_is_variant_and.rs:62:17 | LL | let _ = opt.map(|x| x > 1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_some_and(|x| x > 1)` error: called `map().unwrap_or_default()` on an `Option` value - --> tests/ui/manual_is_variant_and.rs:64:10 + --> tests/ui/manual_is_variant_and.rs:65:10 | LL | .map(|x| x > 1) | __________^ @@ -45,37 +45,37 @@ LL | | .unwrap_or_default(); | |____________________________^ help: use: `is_some_and(|x| x > 1)` error: called `.map() == Some()` - --> tests/ui/manual_is_variant_and.rs:68:13 + --> tests/ui/manual_is_variant_and.rs:69:13 | LL | let _ = Some(2).map(|x| x % 2 == 0) == Some(true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Some(2).is_some_and(|x| x % 2 == 0)` error: called `.map() != Some()` - --> tests/ui/manual_is_variant_and.rs:70:13 + --> tests/ui/manual_is_variant_and.rs:71:13 | LL | let _ = Some(2).map(|x| x % 2 == 0) != Some(true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Some(2).is_none_or(|x| x % 2 != 0)` error: called `.map() == Some()` - --> tests/ui/manual_is_variant_and.rs:72:13 + --> tests/ui/manual_is_variant_and.rs:73:13 | LL | let _ = Some(2).map(|x| x % 2 == 0) == some_true!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Some(2).is_some_and(|x| x % 2 == 0)` error: called `.map() != Some()` - --> tests/ui/manual_is_variant_and.rs:74:13 + --> tests/ui/manual_is_variant_and.rs:75:13 | LL | let _ = Some(2).map(|x| x % 2 == 0) != some_false!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Some(2).is_none_or(|x| x % 2 == 0)` error: called `map().unwrap_or_default()` on an `Option` value - --> tests/ui/manual_is_variant_and.rs:81:18 + --> tests/ui/manual_is_variant_and.rs:82:18 | LL | let _ = opt2.map(char::is_alphanumeric).unwrap_or_default(); // should lint | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_some_and(char::is_alphanumeric)` error: called `map().unwrap_or_default()` on a `Result` value - --> tests/ui/manual_is_variant_and.rs:99:17 + --> tests/ui/manual_is_variant_and.rs:100:17 | LL | let _ = res.map(|x| { | _________________^ @@ -94,7 +94,7 @@ LL ~ }); | error: called `map().unwrap_or_default()` on a `Result` value - --> tests/ui/manual_is_variant_and.rs:104:17 + --> tests/ui/manual_is_variant_and.rs:105:17 | LL | let _ = res.map(|x| x > 1) | _________________^ @@ -103,136 +103,148 @@ LL | | .unwrap_or_default(); | |____________________________^ help: use: `is_ok_and(|x| x > 1)` error: called `.map() == Ok()` - --> tests/ui/manual_is_variant_and.rs:108:13 + --> tests/ui/manual_is_variant_and.rs:109:13 | LL | let _ = Ok::(2).map(|x| x.is_multiple_of(2)) == Ok(true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Ok::(2).is_ok_and(|x| x.is_multiple_of(2))` error: called `.map() != Ok()` - --> tests/ui/manual_is_variant_and.rs:110:13 + --> tests/ui/manual_is_variant_and.rs:111:13 | LL | let _ = Ok::(2).map(|x| x.is_multiple_of(2)) != Ok(true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!Ok::(2).is_ok_and(|x| x.is_multiple_of(2))` error: called `.map() != Ok()` - --> tests/ui/manual_is_variant_and.rs:112:13 + --> tests/ui/manual_is_variant_and.rs:113:13 | LL | let _ = Ok::(2).map(|x| x.is_multiple_of(2)) != Ok(true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!Ok::(2).is_ok_and(|x| x.is_multiple_of(2))` error: called `map().unwrap_or_default()` on a `Result` value - --> tests/ui/manual_is_variant_and.rs:119:18 + --> tests/ui/manual_is_variant_and.rs:120:18 | LL | let _ = res2.map(char::is_alphanumeric).unwrap_or_default(); // should lint | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_ok_and(char::is_alphanumeric)` error: called `.map() != Some()` - --> tests/ui/manual_is_variant_and.rs:132:18 + --> tests/ui/manual_is_variant_and.rs:130: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 + --> tests/ui/manual_is_variant_and.rs:137: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 + --> tests/ui/manual_is_variant_and.rs:144: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 + --> tests/ui/manual_is_variant_and.rs:151: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 + --> tests/ui/manual_is_variant_and.rs:159: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 + --> tests/ui/manual_is_variant_and.rs:166: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 + --> tests/ui/manual_is_variant_and.rs:173: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 + --> tests/ui/manual_is_variant_and.rs:180: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 + --> tests/ui/manual_is_variant_and.rs:193: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 + --> tests/ui/manual_is_variant_and.rs:198: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 + --> tests/ui/manual_is_variant_and.rs:203: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 + --> tests/ui/manual_is_variant_and.rs:208: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 + --> tests/ui/manual_is_variant_and.rs:215: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 + --> tests/ui/manual_is_variant_and.rs:220: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 + --> tests/ui/manual_is_variant_and.rs:225: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 + --> tests/ui/manual_is_variant_and.rs:230:18 | LL | let a1 = b.map(iad) != Ok(false); | ^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!b.is_ok_and(|x| !iad(x))` error: manual implementation of `Option::is_none_or` - --> tests/ui/manual_is_variant_and.rs:242:13 + --> tests/ui/manual_is_variant_and.rs:240:13 | LL | let _ = opt.is_none() || opt.is_some_and(then_fn); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `opt.is_none_or(then_fn)` error: manual implementation of `Option::is_none_or` - --> tests/ui/manual_is_variant_and.rs:245:13 + --> tests/ui/manual_is_variant_and.rs:243:13 | LL | let _ = opt.is_some_and(then_fn) || opt.is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `opt.is_none_or(then_fn)` -error: aborting due to 33 previous errors +error: manual implementation of `Option::is_some_and` + --> tests/ui/manual_is_variant_and.rs:259:5 + | +LL | opt.filter(|x| condition(x)).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `opt.as_ref().is_some_and(|x| condition(x))` + +error: manual implementation of `Option::is_none_or` + --> tests/ui/manual_is_variant_and.rs:261:5 + | +LL | opt.filter(|x| condition(x)).is_none(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `opt.as_ref().is_none_or(|x| !condition(x))` + +error: aborting due to 35 previous errors diff --git a/src/tools/clippy/tests/ui/manual_let_else.rs b/src/tools/clippy/tests/ui/manual_let_else.rs index 4523edec3c764..8271671645efd 100644 --- a/src/tools/clippy/tests/ui/manual_let_else.rs +++ b/src/tools/clippy/tests/ui/manual_let_else.rs @@ -571,3 +571,21 @@ mod issue15914 { }; } } + +fn issue16602(i: Result) { + //~v manual_let_else + _ = match i { + Ok(i) => i, + Err(_) => unsafe { + core::hint::unreachable_unchecked(); + }, + }; + + //~v manual_let_else + _ = match i { + Ok(i) => i, + Err(_) => 'useless_label: { + panic!(); + }, + }; +} diff --git a/src/tools/clippy/tests/ui/manual_let_else.stderr b/src/tools/clippy/tests/ui/manual_let_else.stderr index f4b1644c44baa..8e988cf189b54 100644 --- a/src/tools/clippy/tests/ui/manual_let_else.stderr +++ b/src/tools/clippy/tests/ui/manual_let_else.stderr @@ -585,5 +585,41 @@ LL + return; LL + }; | -error: aborting due to 37 previous errors +error: this could be rewritten as `let...else` + --> tests/ui/manual_let_else.rs:577:5 + | +LL | / _ = match i { +LL | | Ok(i) => i, +LL | | Err(_) => unsafe { +LL | | core::hint::unreachable_unchecked(); +LL | | }, +LL | | }; + | |_____^ + | +help: consider writing + | +LL ~ let Ok(_) = i else { unsafe { +LL + core::hint::unreachable_unchecked(); +LL ~ } };; + | + +error: this could be rewritten as `let...else` + --> tests/ui/manual_let_else.rs:585:5 + | +LL | / _ = match i { +LL | | Ok(i) => i, +LL | | Err(_) => 'useless_label: { +LL | | panic!(); +LL | | }, +LL | | }; + | |_____^ + | +help: consider writing + | +LL ~ let Ok(_) = i else { 'useless_label: { +LL + panic!(); +LL ~ } };; + | + +error: aborting due to 39 previous errors diff --git a/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.fixed b/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.fixed new file mode 100644 index 0000000000000..8fd8b9cd0ffde --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.fixed @@ -0,0 +1,55 @@ +#![warn(clippy::needless_range_loop, clippy::manual_memcpy)] +#![allow(clippy::redundant_slicing, clippy::identity_op)] + +pub fn manual_copy_with_counters(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { + let mut count = 0; + dst[3..src.len()].copy_from_slice(&src[..(src.len() - 3)]); + + let mut count = 0; + dst[..(src.len() - 3)].copy_from_slice(&src[3..]); + + let mut count = 3; + dst[3..(src.len() + 3)].copy_from_slice(&src[..]); + + let mut count = 3; + dst[..src.len()].copy_from_slice(&src[3..(src.len() + 3)]); + + let mut count = 0; + dst[3..(3 + src.len())].copy_from_slice(&src[..(3 + src.len() - 3)]); + + let mut count = 3; + dst[5..src.len()].copy_from_slice(&src[(3 - 2)..((src.len() - 2) + 3 - 5)]); + + let mut count = 2; + dst.copy_from_slice(&src[2..(dst.len() + 2)]); + + let mut count = 5; + dst[3..10].copy_from_slice(&src[5..(10 + 5 - 3)]); + + let mut count = 3; + let mut count2 = 30; + dst[3..(src.len() + 3)].copy_from_slice(&src[..]); + dst2[30..(src.len() + 30)].copy_from_slice(&src[..]); + + // make sure parentheses are added properly to bitwise operators, which have lower precedence than + // arithmetic ones + let mut count = 0 << 1; + dst[(0 << 1)..((1 << 1) + (0 << 1))].copy_from_slice(&src[2..((1 << 1) + 2)]); + + // make sure incrementing expressions without semicolons at the end of loops are handled correctly. + let mut count = 0; + dst[3..src.len()].copy_from_slice(&src[..(src.len() - 3)]); + + // make sure ones where the increment is not at the end of the loop. + // As a possible enhancement, one could adjust the offset in the suggestion according to + // the position. For example, if the increment is at the top of the loop; + // treating the loop counter as if it were initialized 1 greater than the original value. + let mut count = 0; + #[allow(clippy::needless_range_loop)] + for i in 0..src.len() { + count += 1; + dst[i] = src[count]; + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.rs b/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.rs index c83a26cab21ab..9296cefef4f0a 100644 --- a/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.rs +++ b/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.rs @@ -1,5 +1,6 @@ #![warn(clippy::needless_range_loop, clippy::manual_memcpy)] -//@no-rustfix +#![allow(clippy::redundant_slicing, clippy::identity_op)] + pub fn manual_copy_with_counters(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { let mut count = 0; for i in 3..src.len() { diff --git a/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr b/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr index 70da8309f3987..fafa855bad798 100644 --- a/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr +++ b/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr @@ -1,5 +1,5 @@ error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/with_loop_counters.rs:5:5 + --> tests/ui/manual_memcpy/with_loop_counters.rs:6:5 | LL | / for i in 3..src.len() { LL | | @@ -13,7 +13,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::manual_memcpy)]` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/with_loop_counters.rs:13:5 + --> tests/ui/manual_memcpy/with_loop_counters.rs:14:5 | LL | / for i in 3..src.len() { LL | | @@ -24,7 +24,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[..(src.len() - 3)].copy_from_slice(&src[3..]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/with_loop_counters.rs:21:5 + --> tests/ui/manual_memcpy/with_loop_counters.rs:22:5 | LL | / for i in 0..src.len() { LL | | @@ -35,7 +35,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[3..(src.len() + 3)].copy_from_slice(&src[..]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/with_loop_counters.rs:29:5 + --> tests/ui/manual_memcpy/with_loop_counters.rs:30:5 | LL | / for i in 0..src.len() { LL | | @@ -46,7 +46,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[..src.len()].copy_from_slice(&src[3..(src.len() + 3)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/with_loop_counters.rs:37:5 + --> tests/ui/manual_memcpy/with_loop_counters.rs:38:5 | LL | / for i in 3..(3 + src.len()) { LL | | @@ -57,7 +57,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[3..(3 + src.len())].copy_from_slice(&src[..(3 + src.len() - 3)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/with_loop_counters.rs:45:5 + --> tests/ui/manual_memcpy/with_loop_counters.rs:46:5 | LL | / for i in 5..src.len() { LL | | @@ -68,7 +68,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[5..src.len()].copy_from_slice(&src[(3 - 2)..((src.len() - 2) + 3 - 5)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/with_loop_counters.rs:53:5 + --> tests/ui/manual_memcpy/with_loop_counters.rs:54:5 | LL | / for i in 0..dst.len() { LL | | @@ -79,7 +79,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[2..(dst.len() + 2)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/with_loop_counters.rs:61:5 + --> tests/ui/manual_memcpy/with_loop_counters.rs:62:5 | LL | / for i in 3..10 { LL | | @@ -90,7 +90,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[3..10].copy_from_slice(&src[5..(10 + 5 - 3)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/with_loop_counters.rs:70:5 + --> tests/ui/manual_memcpy/with_loop_counters.rs:71:5 | LL | / for i in 0..src.len() { LL | | @@ -108,7 +108,7 @@ LL + dst2[30..(src.len() + 30)].copy_from_slice(&src[..]); | error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/with_loop_counters.rs:82:5 + --> tests/ui/manual_memcpy/with_loop_counters.rs:83:5 | LL | / for i in 0..1 << 1 { LL | | @@ -119,7 +119,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[(0 << 1)..((1 << 1) + (0 << 1))].copy_from_slice(&src[2..((1 << 1) + 2)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/with_loop_counters.rs:91:5 + --> tests/ui/manual_memcpy/with_loop_counters.rs:92:5 | LL | / for i in 3..src.len() { LL | | diff --git a/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.fixed b/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.fixed new file mode 100644 index 0000000000000..8502c740b7126 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.fixed @@ -0,0 +1,175 @@ +#![warn(clippy::manual_memcpy)] +#![allow( + clippy::assigning_clones, + clippy::useless_vec, + clippy::needless_range_loop, + clippy::manual_slice_fill, + clippy::redundant_slicing +)] + +const LOOP_OFFSET: usize = 5000; + +pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { + // plain manual memcpy + dst[..src.len()].copy_from_slice(&src[..]); + + // dst offset memcpy + dst[10..(src.len() + 10)].copy_from_slice(&src[..]); + + // src offset memcpy + dst[..src.len()].copy_from_slice(&src[10..(src.len() + 10)]); + + // src offset memcpy + dst[11..src.len()].copy_from_slice(&src[(11 - 10)..(src.len() - 10)]); + + // overwrite entire dst + dst.copy_from_slice(&src[..dst.len()]); + + // manual copy with branch - can't easily convert to memcpy! + for i in 0..src.len() { + dst[i] = src[i]; + if dst[i] > 5 { + break; + } + } + + // multiple copies - suggest two memcpy statements + dst[10..256].copy_from_slice(&src[(10 - 5)..(256 - 5)]); + dst2[(10 + 500)..(256 + 500)].copy_from_slice(&src[10..256]); + + // this is a reversal - the copy lint shouldn't be triggered + for i in 10..LOOP_OFFSET { + dst[i + LOOP_OFFSET] = src[LOOP_OFFSET - i]; + } + + let some_var = 5; + // Offset in variable + dst[(10 + LOOP_OFFSET)..(LOOP_OFFSET + LOOP_OFFSET)].copy_from_slice(&src[(10 - some_var)..(LOOP_OFFSET - some_var)]); + + // Non continuous copy - don't trigger lint + for i in 0..10 { + dst[i + i] = src[i]; + } + + let src_vec = vec![1, 2, 3, 4, 5]; + let mut dst_vec = vec![0, 0, 0, 0, 0]; + + // make sure vectors are supported + dst_vec[..src_vec.len()].copy_from_slice(&src_vec[..]); + + // lint should not trigger when either + // source or destination type is not + // slice-like, like DummyStruct + struct DummyStruct(i32); + + impl ::std::ops::Index for DummyStruct { + type Output = i32; + + fn index(&self, _: usize) -> &i32 { + &self.0 + } + } + + let src = DummyStruct(5); + let mut dst_vec = vec![0; 10]; + + for i in 0..10 { + dst_vec[i] = src[i]; + } + + // Simplify suggestion (issue #3004) + let src = [0, 1, 2, 3, 4]; + let mut dst = [0, 0, 0, 0, 0, 0]; + let from = 1; + + dst[from..(from + src.len())].copy_from_slice(&src[..(from + src.len() - from)]); + + dst[from..(from + 3)].copy_from_slice(&src[..(from + 3 - from)]); + + #[allow(clippy::identity_op)] + dst[..5].copy_from_slice(&src); + + #[allow(clippy::reversed_empty_ranges)] + dst[..0].copy_from_slice(&src[..0]); + + // `RangeTo` `for` loop - don't trigger lint + for i in 0.. { + dst[i] = src[i]; + } + + // VecDeque - ideally this would work, but would require something like `range_as_slices` + let mut dst = std::collections::VecDeque::from_iter([0; 5]); + let src = std::collections::VecDeque::from_iter([0, 1, 2, 3, 4]); + for i in 0..dst.len() { + dst[i] = src[i]; + } + let src = vec![0, 1, 2, 3, 4]; + for i in 0..dst.len() { + dst[i] = src[i]; + } + + // Range is equal to array length + let src = [0, 1, 2, 3, 4]; + let mut dst = [0; 4]; + dst.copy_from_slice(&src[..4]); + + let mut dst = [0; 6]; + dst[..5].copy_from_slice(&src); + + let mut dst = [0; 5]; + dst.copy_from_slice(&src); + + // Don't trigger lint for following multi-dimensional arrays + let src = [[0; 5]; 5]; + for i in 0..4 { + dst[i] = src[i + 1][i]; + } + for i in 0..5 { + dst[i] = src[i][i]; + } + for i in 0..5 { + dst[i] = src[i][3]; + } + + let src = [0; 5]; + let mut dst = [[0; 5]; 5]; + for i in 0..5 { + dst[i][i] = src[i]; + } + + let src = [[[0; 5]; 5]; 5]; + let mut dst = [0; 5]; + for i in 0..5 { + dst[i] = src[i][i][i]; + } + for i in 0..5 { + dst[i] = src[i][i][0]; + } + for i in 0..5 { + dst[i] = src[i][0][i]; + } + for i in 0..5 { + dst[i] = src[0][i][i]; + } + for i in 0..5 { + dst[i] = src[0][i][1]; + } + for i in 0..5 { + dst[i] = src[i][0][1]; + } + + // Trigger lint + let src = [[0; 5]; 5]; + let mut dst = [0; 5]; + dst.copy_from_slice(&src[0]); + + let src = [[[0; 5]; 5]; 5]; + dst.copy_from_slice(&src[0][1]); +} + +#[warn(clippy::needless_range_loop, clippy::manual_memcpy)] +pub fn manual_clone(src: &[String], dst: &mut [String]) { + dst[..src.len()].clone_from_slice(&src[..]); +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.rs b/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.rs index a3b8763812d72..fc55102fca453 100644 --- a/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.rs +++ b/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.rs @@ -3,10 +3,10 @@ clippy::assigning_clones, clippy::useless_vec, clippy::needless_range_loop, - clippy::manual_slice_fill + clippy::manual_slice_fill, + clippy::redundant_slicing )] -//@no-rustfix const LOOP_OFFSET: usize = 5000; pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { diff --git a/src/tools/clippy/tests/ui/manual_option_as_slice.fixed b/src/tools/clippy/tests/ui/manual_option_as_slice.fixed index 48337d7654dea..3f8674ce0e264 100644 --- a/src/tools/clippy/tests/ui/manual_option_as_slice.fixed +++ b/src/tools/clippy/tests/ui/manual_option_as_slice.fixed @@ -56,7 +56,4 @@ fn check_msrv(x: Option) { _ = x.as_ref().map_or(&[][..], std::slice::from_ref); } -fn main() { - check(Some(1)); - check_msrv(Some(175)); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/manual_option_as_slice.rs b/src/tools/clippy/tests/ui/manual_option_as_slice.rs index e1a97a6b27115..1dd6caea4879d 100644 --- a/src/tools/clippy/tests/ui/manual_option_as_slice.rs +++ b/src/tools/clippy/tests/ui/manual_option_as_slice.rs @@ -66,7 +66,4 @@ fn check_msrv(x: Option) { _ = x.as_ref().map_or(&[][..], std::slice::from_ref); } -fn main() { - check(Some(1)); - check_msrv(Some(175)); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/manual_retain.fixed b/src/tools/clippy/tests/ui/manual_retain.fixed index 016f520e216c0..ea97c488a9ad9 100644 --- a/src/tools/clippy/tests/ui/manual_retain.fixed +++ b/src/tools/clippy/tests/ui/manual_retain.fixed @@ -2,22 +2,7 @@ #![allow(unused, clippy::needless_borrowed_reference, clippy::redundant_clone)] use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque}; -fn main() { - binary_heap_retain(); - btree_set_retain(); - btree_map_retain(); - hash_set_retain(); - hash_map_retain(); - string_retain(); - vec_deque_retain(); - vec_retain(); - _msrv_153(); - _msrv_126(); - _msrv_118(); - - issue_10393(); - issue_12081(); -} +fn main() {} fn binary_heap_retain() { let mut binary_heap = BinaryHeap::from([1, 2, 3]); diff --git a/src/tools/clippy/tests/ui/manual_retain.rs b/src/tools/clippy/tests/ui/manual_retain.rs index 62f9b7b0595d0..5cee4cefa038a 100644 --- a/src/tools/clippy/tests/ui/manual_retain.rs +++ b/src/tools/clippy/tests/ui/manual_retain.rs @@ -2,22 +2,7 @@ #![allow(unused, clippy::needless_borrowed_reference, clippy::redundant_clone)] use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque}; -fn main() { - binary_heap_retain(); - btree_set_retain(); - btree_map_retain(); - hash_set_retain(); - hash_map_retain(); - string_retain(); - vec_deque_retain(); - vec_retain(); - _msrv_153(); - _msrv_126(); - _msrv_118(); - - issue_10393(); - issue_12081(); -} +fn main() {} fn binary_heap_retain() { let mut binary_heap = BinaryHeap::from([1, 2, 3]); diff --git a/src/tools/clippy/tests/ui/manual_retain.stderr b/src/tools/clippy/tests/ui/manual_retain.stderr index e7d3e34b5d7d4..fc562d32d79fb 100644 --- a/src/tools/clippy/tests/ui/manual_retain.stderr +++ b/src/tools/clippy/tests/ui/manual_retain.stderr @@ -1,5 +1,5 @@ error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:25:5 + --> tests/ui/manual_retain.rs:10:5 | LL | binary_heap = binary_heap.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `binary_heap.retain(|x| x % 2 == 0)` @@ -8,43 +8,43 @@ LL | binary_heap = binary_heap.into_iter().filter(|x| x % 2 == 0).collect(); = help: to override `-D warnings` add `#[allow(clippy::manual_retain)]` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:27:5 + --> tests/ui/manual_retain.rs:12:5 | LL | binary_heap = binary_heap.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `binary_heap.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:29:5 + --> tests/ui/manual_retain.rs:14:5 | LL | binary_heap = binary_heap.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `binary_heap.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:34:5 + --> tests/ui/manual_retain.rs:19:5 | LL | tuples = tuples.iter().filter(|&&(ref x, ref y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|&(ref x, ref y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:36:5 + --> tests/ui/manual_retain.rs:21:5 | LL | tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:67:5 + --> tests/ui/manual_retain.rs:52:5 | LL | btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_map.retain(|k, _| k % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:69:5 + --> tests/ui/manual_retain.rs:54:5 | LL | btree_map = btree_map.into_iter().filter(|(_, v)| v % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_map.retain(|_, &mut v| v % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:71:5 + --> tests/ui/manual_retain.rs:56:5 | LL | / btree_map = btree_map LL | | @@ -54,49 +54,49 @@ LL | | .collect(); | |__________________^ help: consider calling `.retain()` instead: `btree_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0))` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:97:5 + --> tests/ui/manual_retain.rs:82:5 | LL | btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:99:5 + --> tests/ui/manual_retain.rs:84:5 | LL | btree_set = btree_set.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:101:5 + --> tests/ui/manual_retain.rs:86:5 | LL | btree_set = btree_set.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:106:5 + --> tests/ui/manual_retain.rs:91:5 | LL | tuples = tuples.iter().filter(|&&(ref x, ref y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|&(ref x, ref y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:108:5 + --> tests/ui/manual_retain.rs:93:5 | LL | tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:139:5 + --> tests/ui/manual_retain.rs:124:5 | LL | hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_map.retain(|k, _| k % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:141:5 + --> tests/ui/manual_retain.rs:126:5 | LL | hash_map = hash_map.into_iter().filter(|(_, v)| v % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_map.retain(|_, &mut v| v % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:143:5 + --> tests/ui/manual_retain.rs:128:5 | LL | / hash_map = hash_map LL | | @@ -106,133 +106,133 @@ LL | | .collect(); | |__________________^ help: consider calling `.retain()` instead: `hash_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0))` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:168:5 + --> tests/ui/manual_retain.rs:153:5 | LL | hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:170:5 + --> tests/ui/manual_retain.rs:155:5 | LL | hash_set = hash_set.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:172:5 + --> tests/ui/manual_retain.rs:157:5 | LL | hash_set = hash_set.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:177:5 + --> tests/ui/manual_retain.rs:162:5 | LL | tuples = tuples.iter().filter(|&&(ref x, ref y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|&(ref x, ref y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:179:5 + --> tests/ui/manual_retain.rs:164:5 | LL | tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:209:5 + --> tests/ui/manual_retain.rs:194:5 | LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `s.retain(|c| c != 'o')` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:222:5 + --> tests/ui/manual_retain.rs:207:5 | LL | vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:224:5 + --> tests/ui/manual_retain.rs:209:5 | LL | vec = vec.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:226:5 + --> tests/ui/manual_retain.rs:211:5 | LL | vec = vec.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:231:5 + --> tests/ui/manual_retain.rs:216:5 | LL | tuples = tuples.iter().filter(|&&(ref x, ref y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|&(ref x, ref y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:233:5 + --> tests/ui/manual_retain.rs:218:5 | LL | tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:256:5 + --> tests/ui/manual_retain.rs:241:5 | LL | vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:258:5 + --> tests/ui/manual_retain.rs:243:5 | LL | vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:260:5 + --> tests/ui/manual_retain.rs:245:5 | LL | vec_deque = vec_deque.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:318:5 + --> tests/ui/manual_retain.rs:303:5 | LL | vec = vec.into_iter().filter(|(x, y)| *x == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|(x, y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:323:5 + --> tests/ui/manual_retain.rs:308:5 | LL | tuples = tuples.into_iter().filter(|(_, n)| *n > 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(_, n)| *n > 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:341:5 + --> tests/ui/manual_retain.rs:326:5 | LL | vec = vec.iter().filter(|&&x| x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|&x| x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:343:5 + --> tests/ui/manual_retain.rs:328:5 | LL | vec = vec.iter().filter(|&&x| x == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|&x| x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:345:5 + --> tests/ui/manual_retain.rs:330:5 | LL | vec = vec.into_iter().filter(|&x| x == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|&x| x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:349:5 + --> tests/ui/manual_retain.rs:334:5 | LL | vec = vec.iter().filter(|&x| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:351:5 + --> tests/ui/manual_retain.rs:336:5 | LL | vec = vec.iter().filter(|&x| *x == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:353:5 + --> tests/ui/manual_retain.rs:338:5 | LL | vec = vec.into_iter().filter(|x| *x == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| *x == 0)` diff --git a/src/tools/clippy/tests/ui/manual_take.fixed b/src/tools/clippy/tests/ui/manual_take.fixed index 5891bd49c81c1..b8f7ca86dfea2 100644 --- a/src/tools/clippy/tests/ui/manual_take.fixed +++ b/src/tools/clippy/tests/ui/manual_take.fixed @@ -1,8 +1,6 @@ #![warn(clippy::manual_take)] fn main() { - msrv_1_39(); - msrv_1_40(); let mut x = true; let mut y = false; diff --git a/src/tools/clippy/tests/ui/manual_take.rs b/src/tools/clippy/tests/ui/manual_take.rs index 89903fcb2416c..39637a8f2e176 100644 --- a/src/tools/clippy/tests/ui/manual_take.rs +++ b/src/tools/clippy/tests/ui/manual_take.rs @@ -1,8 +1,6 @@ #![warn(clippy::manual_take)] fn main() { - msrv_1_39(); - msrv_1_40(); let mut x = true; let mut y = false; diff --git a/src/tools/clippy/tests/ui/manual_take.stderr b/src/tools/clippy/tests/ui/manual_take.stderr index 69ba7778a2758..207711a5a183e 100644 --- a/src/tools/clippy/tests/ui/manual_take.stderr +++ b/src/tools/clippy/tests/ui/manual_take.stderr @@ -1,5 +1,5 @@ error: manual implementation of `mem::take` - --> tests/ui/manual_take.rs:9:25 + --> tests/ui/manual_take.rs:7:25 | LL | let _lint_negated = if x { | _________________________^ @@ -26,7 +26,7 @@ LL + let _lint_negated = !std::mem::take(&mut x); | error: manual implementation of `mem::take` - --> tests/ui/manual_take.rs:62:5 + --> tests/ui/manual_take.rs:60:5 | LL | / if x { LL | | diff --git a/src/tools/clippy/tests/ui/map_flatten.fixed b/src/tools/clippy/tests/ui/map_flatten.fixed new file mode 100644 index 0000000000000..12fca6706e412 --- /dev/null +++ b/src/tools/clippy/tests/ui/map_flatten.fixed @@ -0,0 +1,67 @@ +#![warn(clippy::map_flatten)] +#![allow(clippy::unnecessary_filter_map)] + +// issue #8506, multi-line +#[rustfmt::skip] +fn long_span() { + let _: Option = Some(1) + .and_then(|x| { + //~^ map_flatten + + + if x <= 5 { + Some(x) + } else { + None + } + }); + + let _: Result = Ok(1) + .and_then(|x| { + //~^ map_flatten + + if x == 1 { + Ok(x) + } else { + Err(0) + } + }); + + let result: Result = Ok(2); + fn do_something() { } + let _: Result = result + .and_then(|res| { + //~^ map_flatten + + if res > 0 { + do_something(); + Ok(res) + } else { + Err(0) + } + }); + + let _: Vec<_> = vec![5_i8; 6] + .into_iter() + .filter_map(|some_value| { + //~^ map_flatten + + if some_value > 3 { + Some(some_value) + } else { + None + } + }) + .collect(); +} + +#[allow(clippy::useless_vec)] +fn no_suggestion_if_comments_present() { + let vec = vec![vec![1, 2, 3]]; + let _ = vec + .iter() + // a lovely comment explaining the code in very detail + .flat_map(|x| x.iter()); +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/map_flatten.rs b/src/tools/clippy/tests/ui/map_flatten.rs index 0970da8039a48..3f1b7a268822d 100644 --- a/src/tools/clippy/tests/ui/map_flatten.rs +++ b/src/tools/clippy/tests/ui/map_flatten.rs @@ -1,6 +1,6 @@ #![warn(clippy::map_flatten)] +#![allow(clippy::unnecessary_filter_map)] -//@no-rustfix // issue #8506, multi-line #[rustfmt::skip] fn long_span() { @@ -43,7 +43,7 @@ fn long_span() { } }) .flatten(); - + let _: Vec<_> = vec![5_i8; 6] .into_iter() .map(|some_value| { @@ -71,6 +71,4 @@ fn no_suggestion_if_comments_present() { .flatten(); } -fn main() { - long_span(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/map_unwrap_or.rs b/src/tools/clippy/tests/ui/map_unwrap_or.rs index dccacd7df8af9..37470a50cfbef 100644 --- a/src/tools/clippy/tests/ui/map_unwrap_or.rs +++ b/src/tools/clippy/tests/ui/map_unwrap_or.rs @@ -92,10 +92,7 @@ fn result_methods() { let _ = opt_map!(res, |x| x + 1).unwrap_or_else(|_e| 0); // should not lint } -fn main() { - option_methods(); - result_methods(); -} +fn main() {} #[clippy::msrv = "1.40"] fn msrv_1_40() { diff --git a/src/tools/clippy/tests/ui/map_unwrap_or.stderr b/src/tools/clippy/tests/ui/map_unwrap_or.stderr index bd9e0eeb0bdac..a90da4a97e0c8 100644 --- a/src/tools/clippy/tests/ui/map_unwrap_or.stderr +++ b/src/tools/clippy/tests/ui/map_unwrap_or.stderr @@ -203,13 +203,13 @@ LL ~ }, |x| x + 1); | error: called `map().unwrap_or_else()` on a `Result` value - --> tests/ui/map_unwrap_or.rs:111:13 + --> tests/ui/map_unwrap_or.rs:108:13 | LL | let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or_else(|_e| 0, |x| x + 1)` error: called `map().unwrap_or()` on an `Option` value - --> tests/ui/map_unwrap_or.rs:119:13 + --> tests/ui/map_unwrap_or.rs:116:13 | LL | let _ = opt.map(|x| x > 5).unwrap_or(false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -221,7 +221,7 @@ LL + let _ = opt.map_or(false, |x| x > 5); | error: called `map().unwrap_or(false)` on an `Option` value - --> tests/ui/map_unwrap_or.rs:127:13 + --> tests/ui/map_unwrap_or.rs:124:13 | LL | let _ = opt.map(|x| x > 5).unwrap_or(false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -233,7 +233,7 @@ LL + let _ = opt.is_some_and(|x| x > 5); | error: called `map().unwrap_or()` on an `Option` value - --> tests/ui/map_unwrap_or.rs:164:5 + --> tests/ui/map_unwrap_or.rs:161:5 | LL | x.map(|y| y.0).unwrap_or(&[]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.fixed b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.fixed index dca2536132d79..efdb7cf276692 100644 --- a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.fixed +++ b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.fixed @@ -52,10 +52,7 @@ fn result_methods() { let _ = opt_map!(res, |x| x + 1).unwrap_or_else(|_e| 0); // should not lint } -fn main() { - option_methods(); - result_methods(); -} +fn main() {} fn issue15714() { let o: Option = Some(3); diff --git a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.rs b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.rs index c60cb082ae3c0..5c3f13c2844be 100644 --- a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.rs +++ b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.rs @@ -58,10 +58,7 @@ fn result_methods() { let _ = opt_map!(res, |x| x + 1).unwrap_or_else(|_e| 0); // should not lint } -fn main() { - option_methods(); - result_methods(); -} +fn main() {} fn issue15714() { let o: Option = Some(3); diff --git a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr index 33a865d6769ca..90bb625d7a2ae 100644 --- a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr +++ b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr @@ -20,7 +20,7 @@ LL | | .unwrap_or_else(|_e| 0); | |_______________________________^ help: try: `res.map_or_else(|_e| 0, |x| x + 1)` error: called `map().unwrap_or()` on an `Option` value - --> tests/ui/map_unwrap_or_fixable.rs:69:20 + --> tests/ui/map_unwrap_or_fixable.rs:66:20 | LL | println!("{}", o.map(|y| y + 1).unwrap_or(3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,13 +32,13 @@ LL + println!("{}", o.map_or(3, |y| y + 1)); | error: called `map().unwrap_or_else()` on an `Option` value - --> tests/ui/map_unwrap_or_fixable.rs:71:20 + --> tests/ui/map_unwrap_or_fixable.rs:68:20 | LL | println!("{}", o.map(|y| y + 1).unwrap_or_else(|| 3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `o.map_or_else(|| 3, |y| y + 1)` error: called `map().unwrap_or()` on a `Result` value - --> tests/ui/map_unwrap_or_fixable.rs:73:20 + --> tests/ui/map_unwrap_or_fixable.rs:70:20 | LL | println!("{}", r.map(|y| y + 1).unwrap_or(3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -50,13 +50,13 @@ LL + println!("{}", r.map_or(3, |y| y + 1)); | error: called `map().unwrap_or_else()` on a `Result` value - --> tests/ui/map_unwrap_or_fixable.rs:75:20 + --> tests/ui/map_unwrap_or_fixable.rs:72:20 | LL | println!("{}", r.map(|y| y + 1).unwrap_or_else(|()| 3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `r.map_or_else(|()| 3, |y| y + 1)` error: called `map().unwrap_or(false)` on a `Result` value - --> tests/ui/map_unwrap_or_fixable.rs:78:20 + --> tests/ui/map_unwrap_or_fixable.rs:75:20 | LL | println!("{}", r.map(|y| y == 1).unwrap_or(false)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL + println!("{}", r.is_ok_and(|y| y == 1)); | error: called `map().unwrap_or()` on an `Option` value - --> tests/ui/map_unwrap_or_fixable.rs:84:20 + --> tests/ui/map_unwrap_or_fixable.rs:81:20 | LL | println!("{}", x.map(|y| y + 1).unwrap_or(3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL + println!("{}", x.map_or(3, |y| y + 1)); | error: called `map().unwrap_or()` on a `Result` value - --> tests/ui/map_unwrap_or_fixable.rs:88:20 + --> tests/ui/map_unwrap_or_fixable.rs:85:20 | LL | println!("{}", x.map(|y| y + 1).unwrap_or(3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -92,13 +92,13 @@ LL + println!("{}", x.map_or(3, |y| y + 1)); | error: called `map().unwrap_or_else()` on an `Option` value - --> tests/ui/map_unwrap_or_fixable.rs:92:20 + --> tests/ui/map_unwrap_or_fixable.rs:89:20 | LL | println!("{}", x.map(|y| y + 1).unwrap_or_else(|| 3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.map_or_else(|| 3, |y| y + 1)` error: called `map().unwrap_or_else()` on a `Result` value - --> tests/ui/map_unwrap_or_fixable.rs:96:20 + --> tests/ui/map_unwrap_or_fixable.rs:93:20 | LL | println!("{}", x.map(|y| y + 1).unwrap_or_else(|_| 3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.map_or_else(|_| 3, |y| y + 1)` diff --git a/src/tools/clippy/tests/ui/mem_replace.fixed b/src/tools/clippy/tests/ui/mem_replace.fixed index 94ad1aad3eb75..26aa7aa1b2703 100644 --- a/src/tools/clippy/tests/ui/mem_replace.fixed +++ b/src/tools/clippy/tests/ui/mem_replace.fixed @@ -101,11 +101,7 @@ fn dont_lint_not_used() { std::mem::replace(&mut s, String::default()); } -fn main() { - replace_option_with_none(); - replace_with_default(); - dont_lint_primitive(); -} +fn main() {} #[clippy::msrv = "1.39"] fn msrv_1_39() { diff --git a/src/tools/clippy/tests/ui/mem_replace.rs b/src/tools/clippy/tests/ui/mem_replace.rs index ac79660f0f1ee..cd675f5735a19 100644 --- a/src/tools/clippy/tests/ui/mem_replace.rs +++ b/src/tools/clippy/tests/ui/mem_replace.rs @@ -101,11 +101,7 @@ fn dont_lint_not_used() { std::mem::replace(&mut s, String::default()); } -fn main() { - replace_option_with_none(); - replace_with_default(); - dont_lint_primitive(); -} +fn main() {} #[clippy::msrv = "1.39"] fn msrv_1_39() { diff --git a/src/tools/clippy/tests/ui/mem_replace.stderr b/src/tools/clippy/tests/ui/mem_replace.stderr index 104c985400282..bc374930cf0f2 100644 --- a/src/tools/clippy/tests/ui/mem_replace.stderr +++ b/src/tools/clippy/tests/ui/mem_replace.stderr @@ -131,37 +131,37 @@ LL | let _ = std::mem::replace(&mut slice, &[]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut slice)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:119:13 + --> tests/ui/mem_replace.rs:115:13 | LL | let _ = std::mem::replace(&mut s, String::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)` error: replacing an `Option` with `None` - --> tests/ui/mem_replace.rs:150:13 + --> tests/ui/mem_replace.rs:146:13 | LL | let _ = std::mem::replace(&mut f.0, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `f.0.take()` error: replacing an `Option` with `None` - --> tests/ui/mem_replace.rs:152:13 + --> tests/ui/mem_replace.rs:148:13 | LL | let _ = std::mem::replace(&mut *f, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `(*f).take()` error: replacing an `Option` with `None` - --> tests/ui/mem_replace.rs:154:13 + --> tests/ui/mem_replace.rs:150:13 | LL | let _ = std::mem::replace(&mut b.opt, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `b.opt.take()` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:157:13 + --> tests/ui/mem_replace.rs:153:13 | LL | let _ = std::mem::replace(&mut b.val, String::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut b.val)` error: replacing an `Option` with `Some(..)` - --> tests/ui/mem_replace.rs:164:20 + --> tests/ui/mem_replace.rs:160:20 | LL | let replaced = mem::replace(&mut an_option, Some(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::replace()` instead: `an_option.replace(1)` @@ -170,19 +170,19 @@ LL | let replaced = mem::replace(&mut an_option, Some(1)); = help: to override `-D warnings` add `#[allow(clippy::mem_replace_option_with_some)]` error: replacing an `Option` with `Some(..)` - --> tests/ui/mem_replace.rs:168:20 + --> tests/ui/mem_replace.rs:164:20 | LL | let replaced = mem::replace(an_option, Some(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::replace()` instead: `an_option.replace(1)` error: replacing an `Option` with `Some(..)` - --> tests/ui/mem_replace.rs:173:20 + --> tests/ui/mem_replace.rs:169:20 | LL | let replaced = mem::replace(if b { &mut opt1 } else { &mut opt2 }, Some(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::replace()` instead: `(if b { &mut opt1 } else { &mut opt2 }).replace(1)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:185:20 + --> tests/ui/mem_replace.rs:181:20 | LL | let replaced = std::mem::replace(dbg!(&mut text), String::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(dbg!(&mut text))` diff --git a/src/tools/clippy/tests/ui/mem_replace_no_std.fixed b/src/tools/clippy/tests/ui/mem_replace_no_std.fixed index 669450e59d8b0..4e2d413af6cdf 100644 --- a/src/tools/clippy/tests/ui/mem_replace_no_std.fixed +++ b/src/tools/clippy/tests/ui/mem_replace_no_std.fixed @@ -47,11 +47,7 @@ fn dont_lint_primitive() { let _ = mem::replace(&mut pint, 0); } -fn main() { - replace_option_with_none(); - replace_with_default(); - dont_lint_primitive(); -} +fn main() {} fn issue9824() { struct Foo<'a>(Option<&'a str>); diff --git a/src/tools/clippy/tests/ui/mem_replace_no_std.rs b/src/tools/clippy/tests/ui/mem_replace_no_std.rs index 2cdf1df5196ac..c0892304aba86 100644 --- a/src/tools/clippy/tests/ui/mem_replace_no_std.rs +++ b/src/tools/clippy/tests/ui/mem_replace_no_std.rs @@ -47,11 +47,7 @@ fn dont_lint_primitive() { let _ = mem::replace(&mut pint, 0); } -fn main() { - replace_option_with_none(); - replace_with_default(); - dont_lint_primitive(); -} +fn main() {} fn issue9824() { struct Foo<'a>(Option<&'a str>); diff --git a/src/tools/clippy/tests/ui/mem_replace_no_std.stderr b/src/tools/clippy/tests/ui/mem_replace_no_std.stderr index 926a8288fd31b..34e81a9f07504 100644 --- a/src/tools/clippy/tests/ui/mem_replace_no_std.stderr +++ b/src/tools/clippy/tests/ui/mem_replace_no_std.stderr @@ -29,19 +29,19 @@ LL | let _ = mem::replace(&mut slice, &[]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::mem::take(&mut slice)` error: replacing an `Option` with `None` - --> tests/ui/mem_replace_no_std.rs:80:13 + --> tests/ui/mem_replace_no_std.rs:76:13 | LL | let _ = mem::replace(&mut f.0, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `f.0.take()` error: replacing an `Option` with `None` - --> tests/ui/mem_replace_no_std.rs:82:13 + --> tests/ui/mem_replace_no_std.rs:78:13 | LL | let _ = mem::replace(&mut *f, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `(*f).take()` error: replacing an `Option` with `None` - --> tests/ui/mem_replace_no_std.rs:84:13 + --> tests/ui/mem_replace_no_std.rs:80:13 | LL | let _ = mem::replace(&mut b.opt, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `b.opt.take()` diff --git a/src/tools/clippy/tests/ui/methods.rs b/src/tools/clippy/tests/ui/methods.rs index 9595888b99f83..f73ec563dceb1 100644 --- a/src/tools/clippy/tests/ui/methods.rs +++ b/src/tools/clippy/tests/ui/methods.rs @@ -145,7 +145,7 @@ fn filter_next_back() { *x < 0 } ).next_back(); - + // Check that we don't lint if the caller is not an `Iterator`. let foo = IteratorFalsePositives { foo: 0 }; let _ = foo.filter().next_back(); @@ -154,7 +154,4 @@ fn filter_next_back() { let _ = foo.filter(42).next_back(); } -fn main() { - filter_next(); - filter_next_back(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/methods_unfixable.rs b/src/tools/clippy/tests/ui/methods_unfixable.rs index c19a769f79745..46a5d95eb1b72 100644 --- a/src/tools/clippy/tests/ui/methods_unfixable.rs +++ b/src/tools/clippy/tests/ui/methods_unfixable.rs @@ -1,8 +1,6 @@ #![warn(clippy::filter_next)] //@no-rustfix -fn main() { - issue10029(); -} +fn main() {} pub fn issue10029() { let iter = (0..10); diff --git a/src/tools/clippy/tests/ui/methods_unfixable.stderr b/src/tools/clippy/tests/ui/methods_unfixable.stderr index 76691860f819d..137112ae41795 100644 --- a/src/tools/clippy/tests/ui/methods_unfixable.stderr +++ b/src/tools/clippy/tests/ui/methods_unfixable.stderr @@ -1,11 +1,11 @@ error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead - --> tests/ui/methods_unfixable.rs:9:13 + --> tests/ui/methods_unfixable.rs:7:13 | LL | let _ = iter.filter(|_| true).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `iter.find(|_| true)` | help: you will also need to make `iter` mutable, because `find` takes `&mut self` - --> tests/ui/methods_unfixable.rs:8:9 + --> tests/ui/methods_unfixable.rs:6:9 | LL | let iter = (0..10); | ^^^^ diff --git a/src/tools/clippy/tests/ui/missing_assert_message.stderr b/src/tools/clippy/tests/ui/missing_assert_message.edition2015.stderr similarity index 81% rename from src/tools/clippy/tests/ui/missing_assert_message.stderr rename to src/tools/clippy/tests/ui/missing_assert_message.edition2015.stderr index c4fb7e3b154e4..c5978d706ecbc 100644 --- a/src/tools/clippy/tests/ui/missing_assert_message.stderr +++ b/src/tools/clippy/tests/ui/missing_assert_message.edition2015.stderr @@ -1,5 +1,5 @@ error: assert without any message - --> tests/ui/missing_assert_message.rs:12:5 + --> tests/ui/missing_assert_message.rs:15:5 | LL | assert!(foo()); | ^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | assert!(foo()); = help: to override `-D warnings` add `#[allow(clippy::missing_assert_message)]` error: assert without any message - --> tests/ui/missing_assert_message.rs:14:5 + --> tests/ui/missing_assert_message.rs:17:5 | LL | assert_eq!(foo(), foo()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | assert_eq!(foo(), foo()); = help: consider describing why the failing assert is problematic error: assert without any message - --> tests/ui/missing_assert_message.rs:16:5 + --> tests/ui/missing_assert_message.rs:19:5 | LL | assert_ne!(foo(), foo()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | assert_ne!(foo(), foo()); = help: consider describing why the failing assert is problematic error: assert without any message - --> tests/ui/missing_assert_message.rs:18:5 + --> tests/ui/missing_assert_message.rs:21:5 | LL | debug_assert!(foo()); | ^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | debug_assert!(foo()); = help: consider describing why the failing assert is problematic error: assert without any message - --> tests/ui/missing_assert_message.rs:20:5 + --> tests/ui/missing_assert_message.rs:23:5 | LL | debug_assert_eq!(foo(), foo()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | debug_assert_eq!(foo(), foo()); = help: consider describing why the failing assert is problematic error: assert without any message - --> tests/ui/missing_assert_message.rs:22:5 + --> tests/ui/missing_assert_message.rs:25:5 | LL | debug_assert_ne!(foo(), foo()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | debug_assert_ne!(foo(), foo()); = help: consider describing why the failing assert is problematic error: assert without any message - --> tests/ui/missing_assert_message.rs:28:5 + --> tests/ui/missing_assert_message.rs:31:5 | LL | assert!(bar!(true)); | ^^^^^^^^^^^^^^^^^^^ @@ -57,7 +57,7 @@ LL | assert!(bar!(true)); = help: consider describing why the failing assert is problematic error: assert without any message - --> tests/ui/missing_assert_message.rs:30:5 + --> tests/ui/missing_assert_message.rs:33:5 | LL | assert!(bar!(true, false)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | assert!(bar!(true, false)); = help: consider describing why the failing assert is problematic error: assert without any message - --> tests/ui/missing_assert_message.rs:32:5 + --> tests/ui/missing_assert_message.rs:35:5 | LL | assert_eq!(bar!(true), foo()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | assert_eq!(bar!(true), foo()); = help: consider describing why the failing assert is problematic error: assert without any message - --> tests/ui/missing_assert_message.rs:34:5 + --> tests/ui/missing_assert_message.rs:37:5 | LL | assert_ne!(bar!(true, true), bar!(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | assert_ne!(bar!(true, true), bar!(true)); = help: consider describing why the failing assert is problematic error: assert without any message - --> tests/ui/missing_assert_message.rs:40:5 + --> tests/ui/missing_assert_message.rs:43:5 | LL | assert!(foo(),); | ^^^^^^^^^^^^^^^ @@ -89,7 +89,7 @@ LL | assert!(foo(),); = help: consider describing why the failing assert is problematic error: assert without any message - --> tests/ui/missing_assert_message.rs:42:5 + --> tests/ui/missing_assert_message.rs:45:5 | LL | assert_eq!(foo(), foo(),); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | assert_eq!(foo(), foo(),); = help: consider describing why the failing assert is problematic error: assert without any message - --> tests/ui/missing_assert_message.rs:44:5 + --> tests/ui/missing_assert_message.rs:47:5 | LL | assert_ne!(foo(), foo(),); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | assert_ne!(foo(), foo(),); = help: consider describing why the failing assert is problematic error: assert without any message - --> tests/ui/missing_assert_message.rs:46:5 + --> tests/ui/missing_assert_message.rs:49:5 | LL | debug_assert!(foo(),); | ^^^^^^^^^^^^^^^^^^^^^ @@ -113,7 +113,7 @@ LL | debug_assert!(foo(),); = help: consider describing why the failing assert is problematic error: assert without any message - --> tests/ui/missing_assert_message.rs:48:5 + --> tests/ui/missing_assert_message.rs:51:5 | LL | debug_assert_eq!(foo(), foo(),); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL | debug_assert_eq!(foo(), foo(),); = help: consider describing why the failing assert is problematic error: assert without any message - --> tests/ui/missing_assert_message.rs:50:5 + --> tests/ui/missing_assert_message.rs:53:5 | LL | debug_assert_ne!(foo(), foo(),); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/missing_assert_message.edition2021.stderr b/src/tools/clippy/tests/ui/missing_assert_message.edition2021.stderr new file mode 100644 index 0000000000000..c5978d706ecbc --- /dev/null +++ b/src/tools/clippy/tests/ui/missing_assert_message.edition2021.stderr @@ -0,0 +1,132 @@ +error: assert without any message + --> tests/ui/missing_assert_message.rs:15:5 + | +LL | assert!(foo()); + | ^^^^^^^^^^^^^^ + | + = help: consider describing why the failing assert is problematic + = note: `-D clippy::missing-assert-message` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_assert_message)]` + +error: assert without any message + --> tests/ui/missing_assert_message.rs:17:5 + | +LL | assert_eq!(foo(), foo()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider describing why the failing assert is problematic + +error: assert without any message + --> tests/ui/missing_assert_message.rs:19:5 + | +LL | assert_ne!(foo(), foo()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider describing why the failing assert is problematic + +error: assert without any message + --> tests/ui/missing_assert_message.rs:21:5 + | +LL | debug_assert!(foo()); + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider describing why the failing assert is problematic + +error: assert without any message + --> tests/ui/missing_assert_message.rs:23:5 + | +LL | debug_assert_eq!(foo(), foo()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider describing why the failing assert is problematic + +error: assert without any message + --> tests/ui/missing_assert_message.rs:25:5 + | +LL | debug_assert_ne!(foo(), foo()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider describing why the failing assert is problematic + +error: assert without any message + --> tests/ui/missing_assert_message.rs:31:5 + | +LL | assert!(bar!(true)); + | ^^^^^^^^^^^^^^^^^^^ + | + = help: consider describing why the failing assert is problematic + +error: assert without any message + --> tests/ui/missing_assert_message.rs:33:5 + | +LL | assert!(bar!(true, false)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider describing why the failing assert is problematic + +error: assert without any message + --> tests/ui/missing_assert_message.rs:35:5 + | +LL | assert_eq!(bar!(true), foo()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider describing why the failing assert is problematic + +error: assert without any message + --> tests/ui/missing_assert_message.rs:37:5 + | +LL | assert_ne!(bar!(true, true), bar!(true)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider describing why the failing assert is problematic + +error: assert without any message + --> tests/ui/missing_assert_message.rs:43:5 + | +LL | assert!(foo(),); + | ^^^^^^^^^^^^^^^ + | + = help: consider describing why the failing assert is problematic + +error: assert without any message + --> tests/ui/missing_assert_message.rs:45:5 + | +LL | assert_eq!(foo(), foo(),); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider describing why the failing assert is problematic + +error: assert without any message + --> tests/ui/missing_assert_message.rs:47:5 + | +LL | assert_ne!(foo(), foo(),); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider describing why the failing assert is problematic + +error: assert without any message + --> tests/ui/missing_assert_message.rs:49:5 + | +LL | debug_assert!(foo(),); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider describing why the failing assert is problematic + +error: assert without any message + --> tests/ui/missing_assert_message.rs:51:5 + | +LL | debug_assert_eq!(foo(), foo(),); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider describing why the failing assert is problematic + +error: assert without any message + --> tests/ui/missing_assert_message.rs:53:5 + | +LL | debug_assert_ne!(foo(), foo(),); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider describing why the failing assert is problematic + +error: aborting due to 16 previous errors + diff --git a/src/tools/clippy/tests/ui/missing_assert_message.rs b/src/tools/clippy/tests/ui/missing_assert_message.rs index 2ad8e0127edf7..20ef40af170c1 100644 --- a/src/tools/clippy/tests/ui/missing_assert_message.rs +++ b/src/tools/clippy/tests/ui/missing_assert_message.rs @@ -1,4 +1,7 @@ -#![allow(unused)] +//@revisions: edition2015 edition2021 +//@[edition2015] edition:2015 +//@[edition2021] edition:2021 + #![warn(clippy::missing_assert_message)] macro_rules! bar { diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.rs b/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.rs index 8cef6a80048a5..43b49c6d8b025 100644 --- a/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.rs +++ b/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.rs @@ -1,5 +1,5 @@ //@error-in-other-file: item has both inner and outer attributes -//@no-rustfix + #[path = "auxiliary/submodule.rs"] // don't lint. /// This doc comment should not lint, it could be used to add context to the original module doc mod submodule; diff --git a/src/tools/clippy/tests/ui/must_use_candidates.fixed b/src/tools/clippy/tests/ui/must_use_candidates.fixed index a53e6e9b85bef..10dc5f9157b7f 100644 --- a/src/tools/clippy/tests/ui/must_use_candidates.fixed +++ b/src/tools/clippy/tests/ui/must_use_candidates.fixed @@ -108,3 +108,15 @@ pub fn main() -> std::process::ExitCode { assert_eq!(1, pure(1)); std::process::ExitCode::SUCCESS } + +//~v must_use_candidate +#[must_use] +pub fn result_uninhabited() -> Result { + todo!() +} + +//~v must_use_candidate +#[must_use] +pub fn controlflow_uninhabited() -> std::ops::ControlFlow { + todo!() +} diff --git a/src/tools/clippy/tests/ui/must_use_candidates.rs b/src/tools/clippy/tests/ui/must_use_candidates.rs index 6593d6c68a134..8b898533d01b7 100644 --- a/src/tools/clippy/tests/ui/must_use_candidates.rs +++ b/src/tools/clippy/tests/ui/must_use_candidates.rs @@ -103,3 +103,13 @@ pub fn main() -> std::process::ExitCode { assert_eq!(1, pure(1)); std::process::ExitCode::SUCCESS } + +//~v must_use_candidate +pub fn result_uninhabited() -> Result { + todo!() +} + +//~v must_use_candidate +pub fn controlflow_uninhabited() -> std::ops::ControlFlow { + todo!() +} diff --git a/src/tools/clippy/tests/ui/must_use_candidates.stderr b/src/tools/clippy/tests/ui/must_use_candidates.stderr index 5ddbd02606291..f2ec9b265c450 100644 --- a/src/tools/clippy/tests/ui/must_use_candidates.stderr +++ b/src/tools/clippy/tests/ui/must_use_candidates.stderr @@ -60,5 +60,31 @@ LL + #[must_use] LL | pub fn arcd(_x: Arc) -> bool { | -error: aborting due to 5 previous errors +error: this function could have a `#[must_use]` attribute + --> tests/ui/must_use_candidates.rs:108:8 + | +LL | pub fn result_uninhabited() -> Result { + | ^^^^^^^^^^^^^^^^^^ + | + = note: a future version of Rust will treat `Result` as `T` when `E` is uninhabited wrt `#[must_use]` +help: add the attribute + | +LL + #[must_use] +LL | pub fn result_uninhabited() -> Result { + | + +error: this function could have a `#[must_use]` attribute + --> tests/ui/must_use_candidates.rs:113:8 + | +LL | pub fn controlflow_uninhabited() -> std::ops::ControlFlow { + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: a future version of Rust will treat `ControlFlow` as `C` when `B` is uninhabited wrt `#[must_use]` +help: add the attribute + | +LL + #[must_use] +LL | pub fn controlflow_uninhabited() -> std::ops::ControlFlow { + | + +error: aborting due to 7 previous errors diff --git a/src/tools/clippy/tests/ui/must_use_unit.fixed b/src/tools/clippy/tests/ui/must_use_unit.fixed index 683754a98c828..b9871991b16f0 100644 --- a/src/tools/clippy/tests/ui/must_use_unit.fixed +++ b/src/tools/clippy/tests/ui/must_use_unit.fixed @@ -15,14 +15,10 @@ pub fn must_use_unit() -> () {} pub fn must_use_with_note() {} //~^ must_use_unit -fn main() { - must_use_default(); - must_use_unit(); - must_use_with_note(); +// We should not lint in external macros +external!( + #[must_use] + fn foo() {} +); - // We should not lint in external macros - external!( - #[must_use] - fn foo() {} - ); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/must_use_unit.rs b/src/tools/clippy/tests/ui/must_use_unit.rs index 519b8fa368219..a5865681c8a8e 100644 --- a/src/tools/clippy/tests/ui/must_use_unit.rs +++ b/src/tools/clippy/tests/ui/must_use_unit.rs @@ -18,14 +18,10 @@ pub fn must_use_unit() -> () {} pub fn must_use_with_note() {} //~^ must_use_unit -fn main() { - must_use_default(); - must_use_unit(); - must_use_with_note(); +// We should not lint in external macros +external!( + #[must_use] + fn foo() {} +); - // We should not lint in external macros - external!( - #[must_use] - fn foo() {} - ); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_collect_indirect.fixed b/src/tools/clippy/tests/ui/needless_collect_indirect.fixed new file mode 100644 index 0000000000000..22b9bb6f6a20a --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_collect_indirect.fixed @@ -0,0 +1,344 @@ +#![allow( + clippy::uninlined_format_args, + clippy::useless_vec, + clippy::needless_ifs, + clippy::iter_next_slice, + clippy::iter_count +)] +#![warn(clippy::needless_collect)] + +use std::collections::{BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; + +fn main() { + let sample = [1; 5]; + + //~^ needless_collect + + sample.iter().map(|x| (x, x + 1)).collect::>(); + + //~^ needless_collect + + sample.iter().count(); + + //~^ needless_collect + + sample.iter().next().is_none(); + + //~^ needless_collect + + sample.iter().any(|x| x == &5); + let indirect_negative = sample.iter().collect::>(); + indirect_negative.len(); + indirect_negative + .into_iter() + .map(|x| (*x, *x + 1)) + .collect::>(); + + // #6202 + let a = "a".to_string(); + let sample = vec![a.clone(), "b".to_string(), "c".to_string()]; + + //~^ needless_collect + + sample.into_iter().any(|x| x == a); + + // Fix #5991 + let vec_a = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let vec_b = vec_a.iter().collect::>(); + if vec_b.len() > 3 {} + let other_vec = vec![1, 3, 12, 4, 16, 2]; + let we_got_the_same_numbers = other_vec.iter().filter(|item| vec_b.contains(item)).collect::>(); + + // Fix #6297 + let sample = [1; 5]; + let multiple_indirect = sample.iter().collect::>(); + let sample2 = vec![2, 3]; + if multiple_indirect.is_empty() { + // do something + } else { + let found = sample2 + .iter() + .filter(|i| multiple_indirect.iter().any(|s| **s % **i == 0)) + .collect::>(); + } +} + +mod issue7110 { + // #7110 - lint for type annotation cases + use super::*; + + fn lint_vec(string: &str) -> usize { + + //~^ needless_collect + + string.split('/').count() + } + fn lint_vec_deque() -> usize { + let sample = [1; 5]; + + //~^ needless_collect + + sample.iter().count() + } + fn lint_linked_list() -> usize { + let sample = [1; 5]; + + //~^ needless_collect + + sample.iter().count() + } + fn lint_binary_heap() -> usize { + let sample = [1; 5]; + + //~^ needless_collect + + sample.iter().count() + } + fn dont_lint(string: &str) -> usize { + let buffer: Vec<&str> = string.split('/').collect(); + for buff in &buffer { + println!("{}", buff); + } + buffer.len() + } +} + +mod issue7975 { + use super::*; + + fn direct_mapping_with_used_mutable_reference() -> Vec<()> { + let test_vec: Vec<()> = vec![]; + let mut vec_2: Vec<()> = vec![]; + let mut_ref = &mut vec_2; + let collected_vec: Vec<_> = test_vec.into_iter().map(|_| mut_ref.push(())).collect(); + collected_vec.into_iter().map(|_| mut_ref.push(())).collect() + } + + fn indirectly_mapping_with_used_mutable_reference() -> Vec<()> { + let test_vec: Vec<()> = vec![]; + let mut vec_2: Vec<()> = vec![]; + let mut_ref = &mut vec_2; + let collected_vec: Vec<_> = test_vec.into_iter().map(|_| mut_ref.push(())).collect(); + let iter = collected_vec.into_iter(); + iter.map(|_| mut_ref.push(())).collect() + } + + fn indirect_collect_after_indirect_mapping_with_used_mutable_reference() -> Vec<()> { + let test_vec: Vec<()> = vec![]; + let mut vec_2: Vec<()> = vec![]; + let mut_ref = &mut vec_2; + let collected_vec: Vec<_> = test_vec.into_iter().map(|_| mut_ref.push(())).collect(); + let iter = collected_vec.into_iter(); + let mapped_iter = iter.map(|_| mut_ref.push(())); + mapped_iter.collect() + } +} + +fn allow_test() { + #[allow(clippy::needless_collect)] + let v = [1].iter().collect::>(); + v.into_iter().collect::>(); +} + +mod issue_8553 { + fn test_for() { + let vec = vec![1, 2]; + let w: Vec = vec.iter().map(|i| i * i).collect(); + + for i in 0..2 { + // Do not lint, because this method call is in the loop + w.contains(&i); + } + + for i in 0..2 { + + //~^ needless_collect + + let z: Vec = vec.iter().map(|k| k * k).collect(); + // Do lint + vec.iter().map(|k| k * k).any(|x| x == i); + for j in 0..2 { + // Do not lint, because this method call is in the loop + z.contains(&j); + } + } + + // Do not lint, because this variable is used. + w.contains(&0); + } + + fn test_while() { + let vec = vec![1, 2]; + let x: Vec = vec.iter().map(|i| i * i).collect(); + let mut n = 0; + while n > 1 { + // Do not lint, because this method call is in the loop + x.contains(&n); + n += 1; + } + + while n > 2 { + + //~^ needless_collect + + let z: Vec = vec.iter().map(|k| k * k).collect(); + // Do lint + vec.iter().map(|k| k * k).any(|x| x == n); + n += 1; + while n > 4 { + // Do not lint, because this method call is in the loop + z.contains(&n); + n += 1; + } + } + } + + fn test_loop() { + let vec = vec![1, 2]; + let x: Vec = vec.iter().map(|i| i * i).collect(); + let mut n = 0; + loop { + if n < 1 { + // Do not lint, because this method call is in the loop + x.contains(&n); + n += 1; + } else { + break; + } + } + + loop { + if n < 2 { + + //~^ needless_collect + + let z: Vec = vec.iter().map(|k| k * k).collect(); + // Do lint + vec.iter().map(|k| k * k).any(|x| x == n); + n += 1; + loop { + if n < 4 { + // Do not lint, because this method call is in the loop + z.contains(&n); + n += 1; + } else { + break; + } + } + } else { + break; + } + } + } + + fn test_while_let() { + let vec = vec![1, 2]; + let x: Vec = vec.iter().map(|i| i * i).collect(); + let optional = Some(0); + let mut n = 0; + while let Some(value) = optional { + if n < 1 { + // Do not lint, because this method call is in the loop + x.contains(&n); + n += 1; + } else { + break; + } + } + + while let Some(value) = optional { + + //~^ needless_collect + + let z: Vec = vec.iter().map(|k| k * k).collect(); + if n < 2 { + // Do lint + vec.iter().map(|k| k * k).any(|x| x == n); + n += 1; + } else { + break; + } + + while let Some(value) = optional { + if n < 4 { + // Do not lint, because this method call is in the loop + z.contains(&n); + n += 1; + } else { + break; + } + } + } + } + + fn test_if_cond() { + let vec = vec![1, 2]; + let v: Vec = vec.iter().map(|i| i * i).collect(); + + //~^ needless_collect + + // Do lint + for _ in 0..v.iter().count() { + todo!(); + } + } + + fn test_if_cond_false_case() { + let vec = vec![1, 2]; + let v: Vec = vec.iter().map(|i| i * i).collect(); + let w = v.iter().collect::>(); + // Do not lint, because w is used. + for _ in 0..w.len() { + todo!(); + } + + w.len(); + } + + fn test_while_cond() { + let mut vec = vec![1, 2]; + let mut v: Vec = vec.iter().map(|i| i * i).collect(); + + //~^ needless_collect + + // Do lint + while 1 == v.iter().count() { + todo!(); + } + } + + fn test_while_cond_false_case() { + let mut vec = vec![1, 2]; + let mut v: Vec = vec.iter().map(|i| i * i).collect(); + let mut w = v.iter().collect::>(); + // Do not lint, because w is used. + while 1 == w.len() { + todo!(); + } + + w.len(); + } + + fn test_while_let_cond() { + let mut vec = vec![1, 2]; + let mut v: Vec = vec.iter().map(|i| i * i).collect(); + + //~^ needless_collect + + // Do lint + while let Some(i) = Some(v.iter().count()) { + todo!(); + } + } + + fn test_while_let_cond_false_case() { + let mut vec = vec![1, 2]; + let mut v: Vec = vec.iter().map(|i| i * i).collect(); + let mut w = v.iter().collect::>(); + // Do not lint, because w is used. + while let Some(i) = Some(w.len()) { + todo!(); + } + w.len(); + } +} diff --git a/src/tools/clippy/tests/ui/needless_collect_indirect.rs b/src/tools/clippy/tests/ui/needless_collect_indirect.rs index 69764becfe666..20b7ae91a6b88 100644 --- a/src/tools/clippy/tests/ui/needless_collect_indirect.rs +++ b/src/tools/clippy/tests/ui/needless_collect_indirect.rs @@ -1,6 +1,12 @@ -#![allow(clippy::uninlined_format_args, clippy::useless_vec, clippy::needless_ifs)] +#![allow( + clippy::uninlined_format_args, + clippy::useless_vec, + clippy::needless_ifs, + clippy::iter_next_slice, + clippy::iter_count +)] #![warn(clippy::needless_collect)] -//@no-rustfix + use std::collections::{BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; fn main() { diff --git a/src/tools/clippy/tests/ui/needless_collect_indirect.stderr b/src/tools/clippy/tests/ui/needless_collect_indirect.stderr index 24523c9f97b04..d34f1c37558dc 100644 --- a/src/tools/clippy/tests/ui/needless_collect_indirect.stderr +++ b/src/tools/clippy/tests/ui/needless_collect_indirect.stderr @@ -1,5 +1,5 @@ error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:8:39 + --> tests/ui/needless_collect_indirect.rs:14:39 | LL | let indirect_iter = sample.iter().collect::>(); | ^^^^^^^ @@ -18,7 +18,7 @@ LL ~ sample.iter().map(|x| (x, x + 1)).collect::>(); | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:12:38 + --> tests/ui/needless_collect_indirect.rs:18:38 | LL | let indirect_len = sample.iter().collect::>(); | ^^^^^^^ @@ -35,7 +35,7 @@ LL ~ sample.iter().count(); | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:16:40 + --> tests/ui/needless_collect_indirect.rs:22:40 | LL | let indirect_empty = sample.iter().collect::>(); | ^^^^^^^ @@ -52,7 +52,7 @@ LL ~ sample.iter().next().is_none(); | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:20:43 + --> tests/ui/needless_collect_indirect.rs:26:43 | LL | let indirect_contains = sample.iter().collect::>(); | ^^^^^^^ @@ -69,7 +69,7 @@ LL ~ sample.iter().any(|x| x == &5); | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:34:48 + --> tests/ui/needless_collect_indirect.rs:40:48 | LL | let non_copy_contains = sample.into_iter().collect::>(); | ^^^^^^^ @@ -86,7 +86,7 @@ LL ~ sample.into_iter().any(|x| x == a); | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:65:51 + --> tests/ui/needless_collect_indirect.rs:71:51 | LL | let buffer: Vec<&str> = string.split('/').collect(); | ^^^^^^^ @@ -103,7 +103,7 @@ LL ~ string.split('/').count() | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:72:55 + --> tests/ui/needless_collect_indirect.rs:78:55 | LL | let indirect_len: VecDeque<_> = sample.iter().collect(); | ^^^^^^^ @@ -120,7 +120,7 @@ LL ~ sample.iter().count() | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:79:57 + --> tests/ui/needless_collect_indirect.rs:85:57 | LL | let indirect_len: LinkedList<_> = sample.iter().collect(); | ^^^^^^^ @@ -137,7 +137,7 @@ LL ~ sample.iter().count() | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:86:57 + --> tests/ui/needless_collect_indirect.rs:92:57 | LL | let indirect_len: BinaryHeap<_> = sample.iter().collect(); | ^^^^^^^ @@ -154,7 +154,7 @@ LL ~ sample.iter().count() | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:148:59 + --> tests/ui/needless_collect_indirect.rs:154:59 | LL | let y: Vec = vec.iter().map(|k| k * k).collect(); | ^^^^^^^ @@ -172,7 +172,7 @@ LL ~ vec.iter().map(|k| k * k).any(|x| x == i); | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:175:59 + --> tests/ui/needless_collect_indirect.rs:181:59 | LL | let y: Vec = vec.iter().map(|k| k * k).collect(); | ^^^^^^^ @@ -190,7 +190,7 @@ LL ~ vec.iter().map(|k| k * k).any(|x| x == n); | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:206:63 + --> tests/ui/needless_collect_indirect.rs:212:63 | LL | let y: Vec = vec.iter().map(|k| k * k).collect(); | ^^^^^^^ @@ -208,7 +208,7 @@ LL ~ vec.iter().map(|k| k * k).any(|x| x == n); | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:244:59 + --> tests/ui/needless_collect_indirect.rs:250:59 | LL | let y: Vec = vec.iter().map(|k| k * k).collect(); | ^^^^^^^ @@ -226,7 +226,7 @@ LL ~ vec.iter().map(|k| k * k).any(|x| x == n); | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:271:26 + --> tests/ui/needless_collect_indirect.rs:277:26 | LL | let w = v.iter().collect::>(); | ^^^^^^^ @@ -244,7 +244,7 @@ LL ~ for _ in 0..v.iter().count() { | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:295:30 + --> tests/ui/needless_collect_indirect.rs:301:30 | LL | let mut w = v.iter().collect::>(); | ^^^^^^^ @@ -262,7 +262,7 @@ LL ~ while 1 == v.iter().count() { | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:319:30 + --> tests/ui/needless_collect_indirect.rs:325:30 | LL | let mut w = v.iter().collect::>(); | ^^^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_doc_main.rs b/src/tools/clippy/tests/ui/needless_doc_main.rs index afecd4b47f5eb..803b0bbb0aeff 100644 --- a/src/tools/clippy/tests/ui/needless_doc_main.rs +++ b/src/tools/clippy/tests/ui/needless_doc_main.rs @@ -134,7 +134,4 @@ fn no_false_positives() {} /// ``` fn issue_6022() {} -fn main() { - bad_doctests(); - no_false_positives(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_maybe_sized.fixed b/src/tools/clippy/tests/ui/needless_maybe_sized.fixed index f8b1643969903..92840a888ada5 100644 --- a/src/tools/clippy/tests/ui/needless_maybe_sized.fixed +++ b/src/tools/clippy/tests/ui/needless_maybe_sized.fixed @@ -133,4 +133,13 @@ struct InDerive { struct Refined(T); impl Refined {} +// in proc-macros +fn issue13360() { + #[derive(serde::Serialize)] + #[serde(bound = "T: A")] + struct Foo { + t: std::marker::PhantomData, + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_maybe_sized.rs b/src/tools/clippy/tests/ui/needless_maybe_sized.rs index e4312b40563f1..02242260af1fe 100644 --- a/src/tools/clippy/tests/ui/needless_maybe_sized.rs +++ b/src/tools/clippy/tests/ui/needless_maybe_sized.rs @@ -136,4 +136,13 @@ struct InDerive { struct Refined(T); impl Refined {} +// in proc-macros +fn issue13360() { + #[derive(serde::Serialize)] + #[serde(bound = "T: A")] + struct Foo { + t: std::marker::PhantomData, + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/never_loop.rs b/src/tools/clippy/tests/ui/never_loop.rs index 52470c6ee81bb..7b2d66450f171 100644 --- a/src/tools/clippy/tests/ui/never_loop.rs +++ b/src/tools/clippy/tests/ui/never_loop.rs @@ -447,22 +447,7 @@ fn loop_label() { } } -fn main() { - test1(); - test2(); - test3(); - test4(); - test5(); - test6(); - test7(); - test8(); - test9(); - test10(); - test11(|| 0); - test12(true, false); - test13(); - test14(); -} +fn main() {} fn issue15059() { 'a: for _ in 0..1 { diff --git a/src/tools/clippy/tests/ui/never_loop.stderr b/src/tools/clippy/tests/ui/never_loop.stderr index 49392d971ee32..815758107884c 100644 --- a/src/tools/clippy/tests/ui/never_loop.stderr +++ b/src/tools/clippy/tests/ui/never_loop.stderr @@ -248,7 +248,7 @@ LL | | } | |_________^ error: this loop never actually loops - --> tests/ui/never_loop.rs:468:5 + --> tests/ui/never_loop.rs:453:5 | LL | / 'a: for _ in 0..1 { LL | | @@ -264,7 +264,7 @@ LL ~ | error: this loop never actually loops - --> tests/ui/never_loop.rs:474:5 + --> tests/ui/never_loop.rs:459:5 | LL | / 'a: for i in 0..1 { LL | | @@ -288,7 +288,7 @@ LL ~ | error: this loop never actually loops - --> tests/ui/never_loop.rs:489:5 + --> tests/ui/never_loop.rs:474:5 | LL | / for v in 0..10 { LL | | @@ -311,7 +311,7 @@ LL ~ | error: this loop never actually loops - --> tests/ui/never_loop.rs:500:5 + --> tests/ui/never_loop.rs:485:5 | LL | / 'bar: for _ in 0..100 { LL | | @@ -321,7 +321,7 @@ LL | | } | |_____^ | help: this code is unreachable. Consider moving the reachable parts out - --> tests/ui/never_loop.rs:502:9 + --> tests/ui/never_loop.rs:487:9 | LL | / loop { LL | | @@ -336,7 +336,7 @@ LL + if let Some(_) = (0..100).next() { | error: this loop never actually loops - --> tests/ui/never_loop.rs:502:9 + --> tests/ui/never_loop.rs:487:9 | LL | / loop { LL | | @@ -346,7 +346,7 @@ LL | | } | |_________^ error: this loop never actually loops - --> tests/ui/never_loop.rs:509:5 + --> tests/ui/never_loop.rs:494:5 | LL | / 'foo: for _ in 0..100 { LL | | @@ -356,7 +356,7 @@ LL | | } | |_____^ | help: this code is unreachable. Consider moving the reachable parts out - --> tests/ui/never_loop.rs:511:9 + --> tests/ui/never_loop.rs:496:9 | LL | / loop { LL | | @@ -372,7 +372,7 @@ LL + if let Some(_) = (0..100).next() { | error: this loop never actually loops - --> tests/ui/never_loop.rs:511:9 + --> tests/ui/never_loop.rs:496:9 | LL | / loop { LL | | @@ -383,7 +383,7 @@ LL | | } | |_________^ error: this loop never actually loops - --> tests/ui/never_loop.rs:514:13 + --> tests/ui/never_loop.rs:499:13 | LL | / loop { LL | | @@ -393,7 +393,7 @@ LL | | } | |_____________^ error: this loop never actually loops - --> tests/ui/never_loop.rs:537:5 + --> tests/ui/never_loop.rs:522:5 | LL | / loop { LL | | unsafe { diff --git a/src/tools/clippy/tests/ui/panicking_macros.rs b/src/tools/clippy/tests/ui/panicking_macros.rs index b044be7d54ac5..a9728d4708e6e 100644 --- a/src/tools/clippy/tests/ui/panicking_macros.rs +++ b/src/tools/clippy/tests/ui/panicking_macros.rs @@ -126,15 +126,4 @@ fn debug_assert_msg() { debug_assert_ne!(true, false, "test"); } -fn main() { - panic(); - panic_const(); - todo(); - unimplemented(); - unreachable(); - core_versions(); - assert(); - assert_msg(); - debug_assert(); - debug_assert_msg(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/panicking_overflow_checks.rs b/src/tools/clippy/tests/ui/panicking_overflow_checks.rs index 61dfca8b37286..ecae3130fd505 100644 --- a/src/tools/clippy/tests/ui/panicking_overflow_checks.rs +++ b/src/tools/clippy/tests/ui/panicking_overflow_checks.rs @@ -28,6 +28,4 @@ fn test(a: u32, b: u32, c: u32) { if i - j < i {} } -fn main() { - test(1, 2, 3) -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/println_empty_string.fixed b/src/tools/clippy/tests/ui/println_empty_string.fixed index 6b1039ee8020c..2c2901bc715a6 100644 --- a/src/tools/clippy/tests/ui/println_empty_string.fixed +++ b/src/tools/clippy/tests/ui/println_empty_string.fixed @@ -1,4 +1,4 @@ -#![allow(clippy::match_single_binding)] +#![allow(clippy::match_single_binding, clippy::unnecessary_trailing_comma)] fn main() { println!(); diff --git a/src/tools/clippy/tests/ui/println_empty_string.rs b/src/tools/clippy/tests/ui/println_empty_string.rs index db3b8e1a0eac4..bc2971f54f2cd 100644 --- a/src/tools/clippy/tests/ui/println_empty_string.rs +++ b/src/tools/clippy/tests/ui/println_empty_string.rs @@ -1,4 +1,4 @@ -#![allow(clippy::match_single_binding)] +#![allow(clippy::match_single_binding, clippy::unnecessary_trailing_comma)] fn main() { println!(); diff --git a/src/tools/clippy/tests/ui/regex.rs b/src/tools/clippy/tests/ui/regex.rs index c63d549b75534..699256f22c01c 100644 --- a/src/tools/clippy/tests/ui/regex.rs +++ b/src/tools/clippy/tests/ui/regex.rs @@ -152,8 +152,4 @@ fn regex_creation_in_loops() { } } -fn main() { - syntax_error(); - trivial_regex(); - regex_creation_in_loops(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr index d8f6239764d13..1af70ce5a1f23 100644 --- a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr +++ b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr @@ -1,4 +1,4 @@ -error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a function that returns the unit type `()` --> tests/ui/result_map_unit_fn_fixable.rs:32:5 | LL | x.field.map(do_nothing); @@ -12,7 +12,7 @@ LL - x.field.map(do_nothing); LL + if let Ok(x_field) = x.field { do_nothing(x_field) } | -error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a function that returns the unit type `()` --> tests/ui/result_map_unit_fn_fixable.rs:35:5 | LL | x.field.map(do_nothing); @@ -24,7 +24,7 @@ LL - x.field.map(do_nothing); LL + if let Ok(x_field) = x.field { do_nothing(x_field) } | -error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a function that returns the unit type `()` --> tests/ui/result_map_unit_fn_fixable.rs:38:5 | LL | x.field.map(diverge); @@ -36,7 +36,7 @@ LL - x.field.map(diverge); LL + if let Ok(x_field) = x.field { diverge(x_field) } | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_fixable.rs:45:5 | LL | x.field.map(|value| x.do_result_nothing(value + captured)); @@ -48,7 +48,7 @@ LL - x.field.map(|value| x.do_result_nothing(value + captured)); LL + if let Ok(value) = x.field { x.do_result_nothing(value + captured) } | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_fixable.rs:48:5 | LL | x.field.map(|value| { x.do_result_plus_one(value + captured); }); @@ -60,7 +60,7 @@ LL - x.field.map(|value| { x.do_result_plus_one(value + captured); }); LL + if let Ok(value) = x.field { x.do_result_plus_one(value + captured); } | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_fixable.rs:52:5 | LL | x.field.map(|value| do_nothing(value + captured)); @@ -72,7 +72,7 @@ LL - x.field.map(|value| do_nothing(value + captured)); LL + if let Ok(value) = x.field { do_nothing(value + captured) } | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_fixable.rs:55:5 | LL | x.field.map(|value| { do_nothing(value + captured) }); @@ -84,7 +84,7 @@ LL - x.field.map(|value| { do_nothing(value + captured) }); LL + if let Ok(value) = x.field { do_nothing(value + captured) } | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_fixable.rs:58:5 | LL | x.field.map(|value| { do_nothing(value + captured); }); @@ -96,7 +96,7 @@ LL - x.field.map(|value| { do_nothing(value + captured); }); LL + if let Ok(value) = x.field { do_nothing(value + captured); } | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_fixable.rs:61:5 | LL | x.field.map(|value| { { do_nothing(value + captured); } }); @@ -108,7 +108,7 @@ LL - x.field.map(|value| { { do_nothing(value + captured); } }); LL + if let Ok(value) = x.field { do_nothing(value + captured); } | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_fixable.rs:65:5 | LL | x.field.map(|value| diverge(value + captured)); @@ -120,7 +120,7 @@ LL - x.field.map(|value| diverge(value + captured)); LL + if let Ok(value) = x.field { diverge(value + captured) } | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_fixable.rs:68:5 | LL | x.field.map(|value| { diverge(value + captured) }); @@ -132,7 +132,7 @@ LL - x.field.map(|value| { diverge(value + captured) }); LL + if let Ok(value) = x.field { diverge(value + captured) } | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_fixable.rs:71:5 | LL | x.field.map(|value| { diverge(value + captured); }); @@ -144,7 +144,7 @@ LL - x.field.map(|value| { diverge(value + captured); }); LL + if let Ok(value) = x.field { diverge(value + captured); } | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_fixable.rs:74:5 | LL | x.field.map(|value| { { diverge(value + captured); } }); @@ -156,7 +156,7 @@ LL - x.field.map(|value| { { diverge(value + captured); } }); LL + if let Ok(value) = x.field { diverge(value + captured); } | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_fixable.rs:80:5 | LL | x.field.map(|value| { let y = plus_one(value + captured); }); @@ -168,7 +168,7 @@ LL - x.field.map(|value| { let y = plus_one(value + captured); }); LL + if let Ok(value) = x.field { let y = plus_one(value + captured); } | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_fixable.rs:83:5 | LL | x.field.map(|value| { plus_one(value + captured); }); @@ -180,7 +180,7 @@ LL - x.field.map(|value| { plus_one(value + captured); }); LL + if let Ok(value) = x.field { plus_one(value + captured); } | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_fixable.rs:86:5 | LL | x.field.map(|value| { { plus_one(value + captured); } }); @@ -192,7 +192,7 @@ LL - x.field.map(|value| { { plus_one(value + captured); } }); LL + if let Ok(value) = x.field { plus_one(value + captured); } | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_fixable.rs:90:5 | LL | x.field.map(|ref value| { do_nothing(value + captured) }); @@ -204,7 +204,7 @@ LL - x.field.map(|ref value| { do_nothing(value + captured) }); LL + if let Ok(ref value) = x.field { do_nothing(value + captured) } | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_fixable.rs:93:5 | LL | x.field.map(|value| println!("{value:?}")); diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr index 9f80ec1bbbd07..c7bca9e9e02b3 100644 --- a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr +++ b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr @@ -1,4 +1,4 @@ -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_unfixable.rs:24:5 | LL | x.field.map(|value| { do_nothing(value); do_nothing(value) }); @@ -12,7 +12,7 @@ LL - x.field.map(|value| { do_nothing(value); do_nothing(value) }); LL + if let Ok(value) = x.field { ... } | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_unfixable.rs:29:5 | LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) }); @@ -24,7 +24,7 @@ LL - x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) LL + if let Ok(value) = x.field { ... } | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_unfixable.rs:35:5 | LL | / x.field.map(|value| { @@ -46,7 +46,7 @@ LL - }); LL + if let Ok(value) = x.field { ... } | -error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a closure that returns the unit type `()` --> tests/ui/result_map_unit_fn_unfixable.rs:41:5 | LL | x.field.map(|value| { do_nothing(value); do_nothing(value); }); @@ -58,7 +58,7 @@ LL - x.field.map(|value| { do_nothing(value); do_nothing(value); }); LL + if let Ok(value) = x.field { ... } | -error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a function that returns the unit type `()` --> tests/ui/result_map_unit_fn_unfixable.rs:47:5 | LL | "12".parse::().map(diverge); @@ -70,7 +70,7 @@ LL - "12".parse::().map(diverge); LL + if let Ok(a) = "12".parse::() { diverge(a) } | -error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` +error: called `map(f)` on a `Result` value where `f` is a function that returns the unit type `()` --> tests/ui/result_map_unit_fn_unfixable.rs:55:5 | LL | y.map(do_nothing); diff --git a/src/tools/clippy/tests/ui/set_contains_or_insert.rs b/src/tools/clippy/tests/ui/set_contains_or_insert.rs index ac1d74f8afa4c..b9480cd9172a5 100644 --- a/src/tools/clippy/tests/ui/set_contains_or_insert.rs +++ b/src/tools/clippy/tests/ui/set_contains_or_insert.rs @@ -157,13 +157,7 @@ fn simply_true() -> bool { true } -// This is placed last in order to be able to add new tests without changing line numbers -fn main() { - should_warn_hashset(); - should_warn_btreeset(); - should_not_warn_hashset(); - should_not_warn_btreeset(); -} +fn main() {} fn issue15990(s: &mut HashSet, v: usize) { if !s.contains(&v) { diff --git a/src/tools/clippy/tests/ui/set_contains_or_insert.stderr b/src/tools/clippy/tests/ui/set_contains_or_insert.stderr index 3b06b63182abb..85331514be7a1 100644 --- a/src/tools/clippy/tests/ui/set_contains_or_insert.stderr +++ b/src/tools/clippy/tests/ui/set_contains_or_insert.stderr @@ -128,7 +128,7 @@ LL | borrow_set.insert(value); | ^^^^^^^^^^^^^ error: usage of `HashSet::insert` after `HashSet::contains` - --> tests/ui/set_contains_or_insert.rs:182:11 + --> tests/ui/set_contains_or_insert.rs:176:11 | LL | if !s.contains(&v) { | ^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs index 4dfbe7e0f9f4d..4c6d7df236ef6 100644 --- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs +++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs @@ -12,7 +12,7 @@ clippy::missing_panics_doc, clippy::return_self_not_must_use )] -//@no-rustfix + use std::ops::Mul; use std::rc::{self, Rc}; use std::sync::{self, Arc}; diff --git a/src/tools/clippy/tests/ui/skip_while_next.rs b/src/tools/clippy/tests/ui/skip_while_next.rs index 96f4604ad42dd..6dbb6a2ebb9af 100644 --- a/src/tools/clippy/tests/ui/skip_while_next.rs +++ b/src/tools/clippy/tests/ui/skip_while_next.rs @@ -26,6 +26,4 @@ fn skip_while_next() { let _ = foo.skip_while().next(); } -fn main() { - skip_while_next(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.fixed b/src/tools/clippy/tests/ui/slow_vector_initialization.fixed index a8570366e646d..a13be693e4ec2 100644 --- a/src/tools/clippy/tests/ui/slow_vector_initialization.fixed +++ b/src/tools/clippy/tests/ui/slow_vector_initialization.fixed @@ -1,12 +1,8 @@ #![allow(clippy::useless_vec, clippy::manual_repeat_n)] use std::iter::repeat; -fn main() { - resize_vector(); - extend_vector(); - mixed_extend_resize_vector(); - from_empty_vec(); -} + +fn main() {} fn extend_vector() { // Extend with constant expression diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.rs b/src/tools/clippy/tests/ui/slow_vector_initialization.rs index 52f2a52fbbb86..eda96d0a0f82a 100644 --- a/src/tools/clippy/tests/ui/slow_vector_initialization.rs +++ b/src/tools/clippy/tests/ui/slow_vector_initialization.rs @@ -1,12 +1,8 @@ #![allow(clippy::useless_vec, clippy::manual_repeat_n)] use std::iter::repeat; -fn main() { - resize_vector(); - extend_vector(); - mixed_extend_resize_vector(); - from_empty_vec(); -} + +fn main() {} fn extend_vector() { // Extend with constant expression diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr index e83eef8264724..320f2cacf61b3 100644 --- a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr +++ b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr @@ -1,5 +1,5 @@ error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:14:20 + --> tests/ui/slow_vector_initialization.rs:10:20 | LL | let mut vec1 = Vec::with_capacity(len); | ____________________^ @@ -11,7 +11,7 @@ LL | | vec1.extend(repeat(0).take(len)); = help: to override `-D warnings` add `#[allow(clippy::slow_vector_initialization)]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:20:20 + --> tests/ui/slow_vector_initialization.rs:16:20 | LL | let mut vec2 = Vec::with_capacity(len - 10); | ____________________^ @@ -20,7 +20,7 @@ LL | | vec2.extend(repeat(0).take(len - 10)); | |_________________________________________^ help: consider replacing this with: `vec![0; len - 10]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:29:20 + --> tests/ui/slow_vector_initialization.rs:25:20 | LL | let mut vec4 = Vec::with_capacity(len); | ____________________^ @@ -29,7 +29,7 @@ LL | | vec4.extend(repeat(0).take(vec4.capacity())); | |________________________________________________^ help: consider replacing this with: `vec![0; len]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:41:27 + --> tests/ui/slow_vector_initialization.rs:37:27 | LL | let mut resized_vec = Vec::with_capacity(30); | ___________________________^ @@ -38,7 +38,7 @@ LL | | resized_vec.resize(30, 0); | |_____________________________^ help: consider replacing this with: `vec![0; 30]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:46:26 + --> tests/ui/slow_vector_initialization.rs:42:26 | LL | let mut extend_vec = Vec::with_capacity(30); | __________________________^ @@ -47,7 +47,7 @@ LL | | extend_vec.extend(repeat(0).take(30)); | |_________________________________________^ help: consider replacing this with: `vec![0; 30]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:55:20 + --> tests/ui/slow_vector_initialization.rs:51:20 | LL | let mut vec1 = Vec::with_capacity(len); | ____________________^ @@ -56,7 +56,7 @@ LL | | vec1.resize(len, 0); | |_______________________^ help: consider replacing this with: `vec![0; len]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:65:20 + --> tests/ui/slow_vector_initialization.rs:61:20 | LL | let mut vec3 = Vec::with_capacity(len - 10); | ____________________^ @@ -65,7 +65,7 @@ LL | | vec3.resize(len - 10, 0); | |____________________________^ help: consider replacing this with: `vec![0; len - 10]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:70:20 + --> tests/ui/slow_vector_initialization.rs:66:20 | LL | let mut vec4 = Vec::with_capacity(len); | ____________________^ @@ -74,7 +74,7 @@ LL | | vec4.resize(vec4.capacity(), 0); | |___________________________________^ help: consider replacing this with: `vec![0; len]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:76:12 + --> tests/ui/slow_vector_initialization.rs:72:12 | LL | vec1 = Vec::with_capacity(10); | ____________^ @@ -83,7 +83,7 @@ LL | | vec1.resize(10, 0); | |______________________^ help: consider replacing this with: `vec![0; 10]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:85:20 + --> tests/ui/slow_vector_initialization.rs:81:20 | LL | let mut vec1 = Vec::new(); | ____________________^ @@ -92,7 +92,7 @@ LL | | vec1.resize(len, 0); | |_______________________^ help: consider replacing this with: `vec![0; len]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:91:20 + --> tests/ui/slow_vector_initialization.rs:87:20 | LL | let mut vec3 = Vec::new(); | ____________________^ @@ -101,7 +101,7 @@ LL | | vec3.resize(len - 10, 0); | |____________________________^ help: consider replacing this with: `vec![0; len - 10]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:97:12 + --> tests/ui/slow_vector_initialization.rs:93:12 | LL | vec1 = Vec::new(); | ____________^ @@ -110,7 +110,7 @@ LL | | vec1.resize(10, 0); | |______________________^ help: consider replacing this with: `vec![0; 10]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:102:12 + --> tests/ui/slow_vector_initialization.rs:98:12 | LL | vec1 = vec![]; | ____________^ 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 index 957f472a45448..5e71159ac6c5d 100644 --- a/src/tools/clippy/tests/ui/std_instead_of_core_unfixable.rs +++ b/src/tools/clippy/tests/ui/std_instead_of_core_unfixable.rs @@ -1,5 +1,3 @@ -//@no-rustfix - #![warn(clippy::std_instead_of_core)] #![warn(clippy::std_instead_of_alloc)] #![allow(unused_imports)] 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 index 0cdec56c99274..147b46022126b 100644 --- a/src/tools/clippy/tests/ui/std_instead_of_core_unfixable.stderr +++ b/src/tools/clippy/tests/ui/std_instead_of_core_unfixable.stderr @@ -1,5 +1,5 @@ error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core_unfixable.rs:9:43 + --> tests/ui/std_instead_of_core_unfixable.rs:7:43 | LL | use std::{collections::HashMap, hash::Hash}; | ^^^^ @@ -9,7 +9,7 @@ LL | use std::{collections::HashMap, hash::Hash}; = 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 + --> tests/ui/std_instead_of_core_unfixable.rs:13:22 | LL | use std::{error::Error, vec::Vec, fs::File}; | ^^^^^ @@ -17,7 +17,7 @@ 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 + --> tests/ui/std_instead_of_core_unfixable.rs:13:34 | LL | use std::{error::Error, vec::Vec, fs::File}; | ^^^ diff --git a/src/tools/clippy/tests/ui/str_to_string.fixed b/src/tools/clippy/tests/ui/str_to_string.fixed index 5b76cf78f069d..a8950ab70e566 100644 --- a/src/tools/clippy/tests/ui/str_to_string.fixed +++ b/src/tools/clippy/tests/ui/str_to_string.fixed @@ -1,10 +1,10 @@ #![warn(clippy::str_to_string)] fn main() { - let hello = "hello world".to_owned(); + let hello: String = "hello world".to_owned(); //~^ str_to_string - let msg = &hello[..]; + let msg: &str = &hello[..]; msg.to_owned(); //~^ str_to_string } @@ -19,7 +19,7 @@ fn issue16271(key: &[u8]) { }; } - let _value = t!(str::from_utf8(key)).to_owned(); + let _value: String = t!(str::from_utf8(key)).to_owned(); //~^ str_to_string } @@ -32,22 +32,27 @@ impl GenericWrapper { } fn issue16511(x: Option<&str>) { - let _ = x.map(ToOwned::to_owned); + let _: Option = x.map(str::to_owned); //~^ str_to_string - let _ = x.map(ToOwned::to_owned); + let _: Option = x.map(str::to_owned); //~^ str_to_string - let _ = ["a", "b"].iter().map(ToOwned::to_owned); - //~^ str_to_string + // This should not trigger the lint because ToOwned::to_owned would produce &str, not String. + let _: Vec = ["a", "b"].iter().map(ToString::to_string).collect(); fn mapper String>(f: F) -> String { f("hello") } - let _ = mapper(ToOwned::to_owned); + let _: String = mapper(str::to_owned); //~^ str_to_string - let w = GenericWrapper("hello"); - let _ = w.mapper(ToOwned::to_owned); + let w: GenericWrapper<&str> = GenericWrapper("hello"); + let _: String = w.mapper(str::to_owned); //~^ str_to_string } + +// No lint: non-str types should not trigger str_to_string. See #16569 +fn no_lint_non_str() { + let _: Vec = [1, 2].iter().map(i32::to_string).collect(); +} diff --git a/src/tools/clippy/tests/ui/str_to_string.rs b/src/tools/clippy/tests/ui/str_to_string.rs index f099eb29b1b5f..5d78893f53f6c 100644 --- a/src/tools/clippy/tests/ui/str_to_string.rs +++ b/src/tools/clippy/tests/ui/str_to_string.rs @@ -1,10 +1,10 @@ #![warn(clippy::str_to_string)] fn main() { - let hello = "hello world".to_string(); + let hello: String = "hello world".to_string(); //~^ str_to_string - let msg = &hello[..]; + let msg: &str = &hello[..]; msg.to_string(); //~^ str_to_string } @@ -19,7 +19,7 @@ fn issue16271(key: &[u8]) { }; } - let _value = t!(str::from_utf8(key)).to_string(); + let _value: String = t!(str::from_utf8(key)).to_string(); //~^ str_to_string } @@ -32,22 +32,27 @@ impl GenericWrapper { } fn issue16511(x: Option<&str>) { - let _ = x.map(ToString::to_string); + let _: Option = x.map(ToString::to_string); //~^ str_to_string - let _ = x.map(str::to_string); + let _: Option = x.map(str::to_string); //~^ str_to_string - let _ = ["a", "b"].iter().map(ToString::to_string); - //~^ str_to_string + // This should not trigger the lint because ToOwned::to_owned would produce &str, not String. + let _: Vec = ["a", "b"].iter().map(ToString::to_string).collect(); fn mapper String>(f: F) -> String { f("hello") } - let _ = mapper(ToString::to_string); + let _: String = mapper(ToString::to_string); //~^ str_to_string - let w = GenericWrapper("hello"); - let _ = w.mapper(ToString::to_string); + let w: GenericWrapper<&str> = GenericWrapper("hello"); + let _: String = w.mapper(ToString::to_string); //~^ str_to_string } + +// No lint: non-str types should not trigger str_to_string. See #16569 +fn no_lint_non_str() { + let _: Vec = [1, 2].iter().map(i32::to_string).collect(); +} diff --git a/src/tools/clippy/tests/ui/str_to_string.stderr b/src/tools/clippy/tests/ui/str_to_string.stderr index 296b8e36f28c8..cd4db83e6370c 100644 --- a/src/tools/clippy/tests/ui/str_to_string.stderr +++ b/src/tools/clippy/tests/ui/str_to_string.stderr @@ -1,8 +1,8 @@ error: `to_string()` called on a `&str` - --> tests/ui/str_to_string.rs:4:17 + --> tests/ui/str_to_string.rs:4:25 | -LL | let hello = "hello world".to_string(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"hello world".to_owned()` +LL | let hello: String = "hello world".to_string(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"hello world".to_owned()` | = note: `-D clippy::str-to-string` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::str_to_string)]` @@ -14,40 +14,34 @@ LL | msg.to_string(); | ^^^^^^^^^^^^^^^ help: try: `msg.to_owned()` error: `to_string()` called on a `&str` - --> tests/ui/str_to_string.rs:22:18 + --> tests/ui/str_to_string.rs:22:26 | -LL | let _value = t!(str::from_utf8(key)).to_string(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t!(str::from_utf8(key)).to_owned()` +LL | let _value: String = t!(str::from_utf8(key)).to_string(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t!(str::from_utf8(key)).to_owned()` error: `ToString::to_string` used as `&str` to `String` converter - --> tests/ui/str_to_string.rs:35:19 + --> tests/ui/str_to_string.rs:35:35 | -LL | let _ = x.map(ToString::to_string); - | ^^^^^^^^^^^^^^^^^^^ help: try: `ToOwned::to_owned` +LL | let _: Option = x.map(ToString::to_string); + | ^^^^^^^^^^^^^^^^^^^ help: try: `str::to_owned` error: `ToString::to_string` used as `&str` to `String` converter - --> tests/ui/str_to_string.rs:38:19 + --> tests/ui/str_to_string.rs:38:35 | -LL | let _ = x.map(str::to_string); - | ^^^^^^^^^^^^^^ help: try: `ToOwned::to_owned` +LL | let _: Option = x.map(str::to_string); + | ^^^^^^^^^^^^^^ help: try: `str::to_owned` error: `ToString::to_string` used as `&str` to `String` converter - --> tests/ui/str_to_string.rs:41:35 + --> tests/ui/str_to_string.rs:47:28 | -LL | let _ = ["a", "b"].iter().map(ToString::to_string); - | ^^^^^^^^^^^^^^^^^^^ help: try: `ToOwned::to_owned` +LL | let _: String = mapper(ToString::to_string); + | ^^^^^^^^^^^^^^^^^^^ help: try: `str::to_owned` error: `ToString::to_string` used as `&str` to `String` converter - --> tests/ui/str_to_string.rs:47:20 + --> tests/ui/str_to_string.rs:51:30 | -LL | let _ = mapper(ToString::to_string); - | ^^^^^^^^^^^^^^^^^^^ help: try: `ToOwned::to_owned` +LL | let _: String = w.mapper(ToString::to_string); + | ^^^^^^^^^^^^^^^^^^^ help: try: `str::to_owned` -error: `ToString::to_string` used as `&str` to `String` converter - --> tests/ui/str_to_string.rs:51:22 - | -LL | let _ = w.mapper(ToString::to_string); - | ^^^^^^^^^^^^^^^^^^^ help: try: `ToOwned::to_owned` - -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors diff --git a/src/tools/clippy/tests/ui/string_add.rs b/src/tools/clippy/tests/ui/string_add.rs index 5c7d13ebcd58b..50627a1921a4f 100644 --- a/src/tools/clippy/tests/ui/string_add.rs +++ b/src/tools/clippy/tests/ui/string_add.rs @@ -1,5 +1,5 @@ //@aux-build:proc_macros.rs -//@no-rustfix + extern crate proc_macros; use proc_macros::external; diff --git a/src/tools/clippy/tests/ui/track-diagnostics-clippy.fixed b/src/tools/clippy/tests/ui/track-diagnostics-clippy.fixed new file mode 100644 index 0000000000000..f25ffa7e9afdf --- /dev/null +++ b/src/tools/clippy/tests/ui/track-diagnostics-clippy.fixed @@ -0,0 +1,22 @@ +//@compile-flags: -Z track-diagnostics + +// 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)] + +fn main() { + // Check the provenance of a lint sent through `LintContext::span_lint()` + let a = 3u32; + let b = a; + //~^ unnecessary_cast + + // Check the provenance of a lint sent through `TyCtxt::node_span_lint()` + let c = { + + 42 + //~^ let_and_return + }; +} diff --git a/src/tools/clippy/tests/ui/track-diagnostics-clippy.rs b/src/tools/clippy/tests/ui/track-diagnostics-clippy.rs index 3bae23f198495..8fc1d996c0029 100644 --- a/src/tools/clippy/tests/ui/track-diagnostics-clippy.rs +++ b/src/tools/clippy/tests/ui/track-diagnostics-clippy.rs @@ -1,5 +1,4 @@ //@compile-flags: -Z track-diagnostics -//@no-rustfix // Normalize the emitted location so this doesn't need // updating everytime someone adds or removes a line. diff --git a/src/tools/clippy/tests/ui/transmute_null_to_fn.rs b/src/tools/clippy/tests/ui/transmute_null_to_fn.rs index 4712374af934f..9ce097d124ab8 100644 --- a/src/tools/clippy/tests/ui/transmute_null_to_fn.rs +++ b/src/tools/clippy/tests/ui/transmute_null_to_fn.rs @@ -41,7 +41,4 @@ fn issue_11485() { } } -fn main() { - one_liners(); - transmute_const(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/transmute_ref_to_ref.fixed b/src/tools/clippy/tests/ui/transmute_ref_to_ref.fixed new file mode 100644 index 0000000000000..0ec59ea810aed --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref.fixed @@ -0,0 +1,38 @@ +#![deny(clippy::transmute_ptr_to_ptr)] +#![allow(dead_code, clippy::missing_transmute_annotations, clippy::cast_slice_different_sizes)] + +fn main() { + unsafe { + let single_u64: &[u64] = &[0xDEAD_BEEF_DEAD_BEEF]; + let bools: &[bool] = unsafe { &*(single_u64 as *const [u64] as *const [bool]) }; + //~^ transmute_ptr_to_ptr + + let a: &[u32] = &[0x12345678, 0x90ABCDEF, 0xFEDCBA09, 0x87654321]; + let b: &[u8] = unsafe { &*(a as *const [u32] as *const [u8]) }; + //~^ transmute_ptr_to_ptr + + let bytes = &[1u8, 2u8, 3u8, 4u8] as &[u8]; + let alt_slice: &[u32] = unsafe { &*(bytes as *const [u8] as *const [u32]) }; + //~^ transmute_ptr_to_ptr + } +} + +fn issue16104(make_ptr: fn() -> *const u32) { + macro_rules! call { + ($x:expr) => { + $x() + }; + } + macro_rules! take_ref { + ($x:expr) => { + &$x + }; + } + + unsafe { + let _: *const f32 = call!(make_ptr).cast::(); + //~^ transmute_ptr_to_ptr + let _: &f32 = &*(take_ref!(1u32) as *const u32 as *const f32); + //~^ transmute_ptr_to_ptr + } +} diff --git a/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs b/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs index ed8fb80832918..78f3d1fe0bb24 100644 --- a/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs @@ -1,7 +1,5 @@ -//@no-rustfix - #![deny(clippy::transmute_ptr_to_ptr)] -#![allow(dead_code, clippy::missing_transmute_annotations)] +#![allow(dead_code, clippy::missing_transmute_annotations, clippy::cast_slice_different_sizes)] fn main() { unsafe { diff --git a/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr b/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr index 1b845ef859d88..13ee64574f7b9 100644 --- a/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr @@ -1,29 +1,29 @@ error: transmute from a reference to a reference - --> tests/ui/transmute_ref_to_ref.rs:9:39 + --> tests/ui/transmute_ref_to_ref.rs:7:39 | LL | let bools: &[bool] = unsafe { std::mem::transmute(single_u64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(single_u64 as *const [u64] as *const [bool])` | note: the lint level is defined here - --> tests/ui/transmute_ref_to_ref.rs:3:9 + --> tests/ui/transmute_ref_to_ref.rs:1:9 | LL | #![deny(clippy::transmute_ptr_to_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a reference to a reference - --> tests/ui/transmute_ref_to_ref.rs:13:33 + --> tests/ui/transmute_ref_to_ref.rs:11:33 | LL | let b: &[u8] = unsafe { std::mem::transmute(a) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const [u32] as *const [u8])` error: transmute from a reference to a reference - --> tests/ui/transmute_ref_to_ref.rs:17:42 + --> tests/ui/transmute_ref_to_ref.rs:15:42 | LL | let alt_slice: &[u32] = unsafe { std::mem::transmute(bytes) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(bytes as *const [u8] as *const [u32])` error: transmute from a pointer to a pointer - --> tests/ui/transmute_ref_to_ref.rs:35:29 + --> tests/ui/transmute_ref_to_ref.rs:33:29 | LL | let _: *const f32 = std::mem::transmute(call!(make_ptr)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL + let _: *const f32 = call!(make_ptr).cast::(); | error: transmute from a reference to a reference - --> tests/ui/transmute_ref_to_ref.rs:37:23 + --> tests/ui/transmute_ref_to_ref.rs:35:23 | LL | let _: &f32 = std::mem::transmute(take_ref!(1u32)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(take_ref!(1u32) as *const u32 as *const f32)` diff --git a/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.fixed b/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.fixed new file mode 100644 index 0000000000000..3a1c75f168546 --- /dev/null +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.fixed @@ -0,0 +1,30 @@ +#![deny(clippy::transmute_ptr_to_ptr)] +#![allow(dead_code, clippy::missing_transmute_annotations, clippy::cast_slice_different_sizes)] +#![feature(lang_items)] +#![no_std] + +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} + +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + loop {} +} + +fn main() { + unsafe { + let single_u64: &[u64] = &[0xDEAD_BEEF_DEAD_BEEF]; + let bools: &[bool] = unsafe { &*(single_u64 as *const [u64] as *const [bool]) }; + //~^ transmute_ptr_to_ptr + + let a: &[u32] = &[0x12345678, 0x90ABCDEF, 0xFEDCBA09, 0x87654321]; + let b: &[u8] = unsafe { &*(a as *const [u32] as *const [u8]) }; + //~^ transmute_ptr_to_ptr + + let bytes = &[1u8, 2u8, 3u8, 4u8] as &[u8]; + let alt_slice: &[u32] = unsafe { &*(bytes as *const [u8] as *const [u32]) }; + //~^ transmute_ptr_to_ptr + } +} diff --git a/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.rs b/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.rs index faa776f2afcec..7ed885bbbb07e 100644 --- a/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.rs +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.rs @@ -1,7 +1,5 @@ -//@no-rustfix - #![deny(clippy::transmute_ptr_to_ptr)] -#![allow(dead_code, clippy::missing_transmute_annotations)] +#![allow(dead_code, clippy::missing_transmute_annotations, clippy::cast_slice_different_sizes)] #![feature(lang_items)] #![no_std] diff --git a/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.stderr b/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.stderr index 9aa9ed928a4d5..136a9b21fb9e9 100644 --- a/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.stderr +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.stderr @@ -1,23 +1,23 @@ error: transmute from a reference to a reference - --> tests/ui/transmute_ref_to_ref_no_std.rs:21:39 + --> tests/ui/transmute_ref_to_ref_no_std.rs:19:39 | LL | let bools: &[bool] = unsafe { core::mem::transmute(single_u64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(single_u64 as *const [u64] as *const [bool])` | note: the lint level is defined here - --> tests/ui/transmute_ref_to_ref_no_std.rs:3:9 + --> tests/ui/transmute_ref_to_ref_no_std.rs:1:9 | LL | #![deny(clippy::transmute_ptr_to_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a reference to a reference - --> tests/ui/transmute_ref_to_ref_no_std.rs:25:33 + --> tests/ui/transmute_ref_to_ref_no_std.rs:23:33 | LL | let b: &[u8] = unsafe { core::mem::transmute(a) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const [u32] as *const [u8])` error: transmute from a reference to a reference - --> tests/ui/transmute_ref_to_ref_no_std.rs:29:42 + --> tests/ui/transmute_ref_to_ref_no_std.rs:27:42 | LL | let alt_slice: &[u32] = unsafe { core::mem::transmute(bytes) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(bytes as *const [u8] as *const [u32])` diff --git a/src/tools/clippy/tests/ui/transmuting_null.rs b/src/tools/clippy/tests/ui/transmuting_null.rs index efa4c5cfdc2d7..c2de798ab3082 100644 --- a/src/tools/clippy/tests/ui/transmuting_null.rs +++ b/src/tools/clippy/tests/ui/transmuting_null.rs @@ -57,10 +57,4 @@ fn transmute_pointer_creators() { } } -fn main() { - one_liners(); - transmute_const(); - transmute_const_int(); - transumute_single_expr_blocks(); - transmute_pointer_creators(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/try_err.fixed b/src/tools/clippy/tests/ui/try_err.fixed index ea509f9a2da87..bec366f4fd604 100644 --- a/src/tools/clippy/tests/ui/try_err.fixed +++ b/src/tools/clippy/tests/ui/try_err.fixed @@ -107,24 +107,17 @@ fn calling_macro() -> Result { Ok(5) } -fn main() { - basic_test().unwrap(); - into_test().unwrap(); - negative_test().unwrap(); - closure_matches_test().unwrap(); - closure_into_test().unwrap(); - calling_macro().unwrap(); - - // We don't want to lint in external macros - external! { - pub fn try_err_fn() -> Result { - let err: i32 = 1; - // To avoid warnings during rustfix - if true { Err(err)? } else { Ok(2) } - } +// We don't want to lint in external macros +external! { + pub fn try_err_fn() -> Result { + let err: i32 = 1; + // To avoid warnings during rustfix + if true { Err(err)? } else { Ok(2) } } } +fn main() {} + #[inline_macros] pub fn macro_inside(fail: bool) -> Result { if fail { diff --git a/src/tools/clippy/tests/ui/try_err.rs b/src/tools/clippy/tests/ui/try_err.rs index 295f7bd7089b9..9c10acd2ce0ad 100644 --- a/src/tools/clippy/tests/ui/try_err.rs +++ b/src/tools/clippy/tests/ui/try_err.rs @@ -107,24 +107,17 @@ fn calling_macro() -> Result { Ok(5) } -fn main() { - basic_test().unwrap(); - into_test().unwrap(); - negative_test().unwrap(); - closure_matches_test().unwrap(); - closure_into_test().unwrap(); - calling_macro().unwrap(); - - // We don't want to lint in external macros - external! { - pub fn try_err_fn() -> Result { - let err: i32 = 1; - // To avoid warnings during rustfix - if true { Err(err)? } else { Ok(2) } - } +// We don't want to lint in external macros +external! { + pub fn try_err_fn() -> Result { + let err: i32 = 1; + // To avoid warnings during rustfix + if true { Err(err)? } else { Ok(2) } } } +fn main() {} + #[inline_macros] pub fn macro_inside(fail: bool) -> Result { if fail { diff --git a/src/tools/clippy/tests/ui/try_err.stderr b/src/tools/clippy/tests/ui/try_err.stderr index 50c2b092d6c87..3ca51e9d88915 100644 --- a/src/tools/clippy/tests/ui/try_err.stderr +++ b/src/tools/clippy/tests/ui/try_err.stderr @@ -45,31 +45,31 @@ LL | Err(_) => Err(inline!(1))?, = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: returning an `Err(_)` with the `?` operator - --> tests/ui/try_err.rs:131:9 + --> tests/ui/try_err.rs:124:9 | LL | Err(inline!(inline!(String::from("aasdfasdfasdfa"))))?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Err(inline!(inline!(String::from("aasdfasdfasdfa"))))` error: returning an `Err(_)` with the `?` operator - --> tests/ui/try_err.rs:139:9 + --> tests/ui/try_err.rs:132:9 | LL | Err(io::ErrorKind::WriteZero)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))` error: returning an `Err(_)` with the `?` operator - --> tests/ui/try_err.rs:142:9 + --> tests/ui/try_err.rs:135:9 | LL | Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))` error: returning an `Err(_)` with the `?` operator - --> tests/ui/try_err.rs:151:9 + --> tests/ui/try_err.rs:144:9 | LL | Err(io::ErrorKind::NotFound)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))` error: returning an `Err(_)` with the `?` operator - --> tests/ui/try_err.rs:161:16 + --> tests/ui/try_err.rs:154:16 | LL | return Err(42)?; | ^^^^^^^^ help: try: `Err(42)` diff --git a/src/tools/clippy/tests/ui/unchecked_time_subtraction.fixed b/src/tools/clippy/tests/ui/unchecked_time_subtraction.fixed index 830b737f18e7a..5fe51dd5ba7ca 100644 --- a/src/tools/clippy/tests/ui/unchecked_time_subtraction.fixed +++ b/src/tools/clippy/tests/ui/unchecked_time_subtraction.fixed @@ -25,8 +25,7 @@ fn main() { let _ = dur1.checked_sub(dur2).unwrap(); //~^ unchecked_time_subtraction - let _ = Duration::from_secs(10).checked_sub(Duration::from_secs(5)).unwrap(); - //~^ unchecked_time_subtraction + let _ = Duration::from_secs(10) - Duration::from_secs(5); let _ = second.checked_sub(dur1).unwrap(); //~^ unchecked_time_subtraction @@ -55,8 +54,17 @@ fn issue16234() { }; } - duration!(0).checked_sub(duration!(1)).unwrap(); + let d = duration!(0); + d.checked_sub(duration!(1)).unwrap(); //~^ unchecked_time_subtraction - let _ = duration!(0).checked_sub(duration!(1)).unwrap(); + let _ = d.checked_sub(duration!(1)).unwrap(); //~^ unchecked_time_subtraction } + +fn issue16499() { + let _ = Duration::from_millis(2) - Duration::from_millis(1); + let _ = Duration::new(10000, 0) - Duration::from_secs(1); + let _ = Duration::from_nanos_u128(1000) - Duration::from_nanos(100); + let _ = Duration::from_secs_f32(1.5) - Duration::from_secs_f64(0.5); + let _ = Duration::from_mins(70) - Duration::from_hours(1); +} diff --git a/src/tools/clippy/tests/ui/unchecked_time_subtraction.rs b/src/tools/clippy/tests/ui/unchecked_time_subtraction.rs index e41860157c41e..466d96a9a6064 100644 --- a/src/tools/clippy/tests/ui/unchecked_time_subtraction.rs +++ b/src/tools/clippy/tests/ui/unchecked_time_subtraction.rs @@ -26,7 +26,6 @@ fn main() { //~^ unchecked_time_subtraction let _ = Duration::from_secs(10) - Duration::from_secs(5); - //~^ unchecked_time_subtraction let _ = second - dur1; //~^ unchecked_time_subtraction @@ -55,8 +54,17 @@ fn issue16234() { }; } - duration!(0).sub(duration!(1)); + let d = duration!(0); + d.sub(duration!(1)); //~^ unchecked_time_subtraction - let _ = duration!(0) - duration!(1); + let _ = d - duration!(1); //~^ unchecked_time_subtraction } + +fn issue16499() { + let _ = Duration::from_millis(2) - Duration::from_millis(1); + let _ = Duration::new(10000, 0) - Duration::from_secs(1); + let _ = Duration::from_nanos_u128(1000) - Duration::from_nanos(100); + let _ = Duration::from_secs_f32(1.5) - Duration::from_secs_f64(0.5); + let _ = Duration::from_mins(70) - Duration::from_hours(1); +} diff --git a/src/tools/clippy/tests/ui/unchecked_time_subtraction.stderr b/src/tools/clippy/tests/ui/unchecked_time_subtraction.stderr index fa4bd1db81aee..b71e2c474f2ea 100644 --- a/src/tools/clippy/tests/ui/unchecked_time_subtraction.stderr +++ b/src/tools/clippy/tests/ui/unchecked_time_subtraction.stderr @@ -32,31 +32,25 @@ LL | let _ = dur1 - dur2; | ^^^^^^^^^^^ help: try: `dur1.checked_sub(dur2).unwrap()` error: unchecked subtraction of a `Duration` - --> tests/ui/unchecked_time_subtraction.rs:28:13 - | -LL | let _ = Duration::from_secs(10) - Duration::from_secs(5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Duration::from_secs(10).checked_sub(Duration::from_secs(5)).unwrap()` - -error: unchecked subtraction of a `Duration` - --> tests/ui/unchecked_time_subtraction.rs:31:13 + --> tests/ui/unchecked_time_subtraction.rs:30:13 | LL | let _ = second - dur1; | ^^^^^^^^^^^^^ help: try: `second.checked_sub(dur1).unwrap()` error: unchecked subtraction of a `Duration` - --> tests/ui/unchecked_time_subtraction.rs:35:13 + --> tests/ui/unchecked_time_subtraction.rs:34:13 | LL | let _ = 2 * dur1 - dur2; | ^^^^^^^^^^^^^^^ help: try: `(2 * dur1).checked_sub(dur2).unwrap()` error: unchecked subtraction of a `Duration` - --> tests/ui/unchecked_time_subtraction.rs:42:5 + --> tests/ui/unchecked_time_subtraction.rs:41:5 | LL | Duration::ZERO.sub(Duration::MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Duration::ZERO.checked_sub(Duration::MAX).unwrap()` error: unchecked subtraction of a `Duration` - --> tests/ui/unchecked_time_subtraction.rs:45:13 + --> tests/ui/unchecked_time_subtraction.rs:44:13 | LL | let _ = Duration::ZERO - Duration::MAX; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Duration::ZERO.checked_sub(Duration::MAX).unwrap()` @@ -64,14 +58,14 @@ LL | let _ = Duration::ZERO - Duration::MAX; error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:58:5 | -LL | duration!(0).sub(duration!(1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `duration!(0).checked_sub(duration!(1)).unwrap()` +LL | d.sub(duration!(1)); + | ^^^^^^^^^^^^^^^^^^^ help: try: `d.checked_sub(duration!(1)).unwrap()` error: unchecked subtraction of a `Duration` --> tests/ui/unchecked_time_subtraction.rs:60:13 | -LL | let _ = duration!(0) - duration!(1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `duration!(0).checked_sub(duration!(1)).unwrap()` +LL | let _ = d - duration!(1); + | ^^^^^^^^^^^^^^^^ help: try: `d.checked_sub(duration!(1)).unwrap()` -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/unchecked_time_subtraction_unfixable.rs b/src/tools/clippy/tests/ui/unchecked_time_subtraction_unfixable.rs index 4b6a5ca156209..6c3777eec915a 100644 --- a/src/tools/clippy/tests/ui/unchecked_time_subtraction_unfixable.rs +++ b/src/tools/clippy/tests/ui/unchecked_time_subtraction_unfixable.rs @@ -20,3 +20,12 @@ fn main() { //~^ unchecked_time_subtraction //~| unchecked_time_subtraction } + +fn issue16499() { + let _ = Duration::from_millis(1) - Duration::from_millis(2); + //~^ unchecked_time_subtraction + let _ = Duration::from_millis(1) - Duration::from_mins(2); + //~^ unchecked_time_subtraction + let _ = Duration::from_nanos(1) - Duration::from_secs(1); + //~^ unchecked_time_subtraction +} diff --git a/src/tools/clippy/tests/ui/unchecked_time_subtraction_unfixable.stderr b/src/tools/clippy/tests/ui/unchecked_time_subtraction_unfixable.stderr index 017e5b1c7c11e..a48676bf5c168 100644 --- a/src/tools/clippy/tests/ui/unchecked_time_subtraction_unfixable.stderr +++ b/src/tools/clippy/tests/ui/unchecked_time_subtraction_unfixable.stderr @@ -25,5 +25,29 @@ error: unchecked subtraction of a `Duration` LL | let _ = instant1 - dur2 - dur3; | ^^^^^^^^^^^^^^^ help: try: `instant1.checked_sub(dur2).unwrap()` -error: aborting due to 4 previous errors +error: unchecked subtraction of two `Duration` that will underflow + --> tests/ui/unchecked_time_subtraction_unfixable.rs:25:13 + | +LL | let _ = Duration::from_millis(1) - Duration::from_millis(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: if this is intentional, consider allowing the lint + +error: unchecked subtraction of two `Duration` that will underflow + --> tests/ui/unchecked_time_subtraction_unfixable.rs:27:13 + | +LL | let _ = Duration::from_millis(1) - Duration::from_mins(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: if this is intentional, consider allowing the lint + +error: unchecked subtraction of two `Duration` that will underflow + --> tests/ui/unchecked_time_subtraction_unfixable.rs:29:13 + | +LL | let _ = Duration::from_nanos(1) - Duration::from_secs(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: if this is intentional, consider allowing the lint + +error: aborting due to 7 previous errors diff --git a/src/tools/clippy/tests/ui/unconditional_recursion.rs b/src/tools/clippy/tests/ui/unconditional_recursion.rs index e4dd33a8eeea7..20b4198d63926 100644 --- a/src/tools/clippy/tests/ui/unconditional_recursion.rs +++ b/src/tools/clippy/tests/ui/unconditional_recursion.rs @@ -1,5 +1,3 @@ -//@no-rustfix - #![warn(clippy::unconditional_recursion)] #![allow( clippy::partialeq_ne_impl, diff --git a/src/tools/clippy/tests/ui/unconditional_recursion.stderr b/src/tools/clippy/tests/ui/unconditional_recursion.stderr index c6eaa6a0775c1..5edccf9593da9 100644 --- a/src/tools/clippy/tests/ui/unconditional_recursion.stderr +++ b/src/tools/clippy/tests/ui/unconditional_recursion.stderr @@ -1,5 +1,5 @@ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:51:5 + --> tests/ui/unconditional_recursion.rs:49:5 | LL | fn ne(&self, other: &Self) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -12,7 +12,7 @@ LL | self.ne(other) = help: to override `-D warnings` add `#[allow(unconditional_recursion)]` error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:56:5 + --> tests/ui/unconditional_recursion.rs:54:5 | LL | fn eq(&self, other: &Self) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -23,7 +23,7 @@ LL | self.eq(other) = help: a `loop` may express intention better if this is on purpose error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:235:5 + --> tests/ui/unconditional_recursion.rs:233:5 | LL | fn to_string(&self) -> String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -34,7 +34,7 @@ LL | self.to_string() = help: a `loop` may express intention better if this is on purpose error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:245:5 + --> tests/ui/unconditional_recursion.rs:243:5 | LL | fn to_string(&self) -> String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -45,7 +45,7 @@ LL | x.to_string() = help: a `loop` may express intention better if this is on purpose error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:256:5 + --> tests/ui/unconditional_recursion.rs:254:5 | LL | fn to_string(&self) -> String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -56,7 +56,7 @@ LL | (self as &Self).to_string() = help: a `loop` may express intention better if this is on purpose error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:17:5 + --> tests/ui/unconditional_recursion.rs:15:5 | LL | / fn ne(&self, other: &Self) -> bool { LL | | @@ -66,7 +66,7 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:20:9 + --> tests/ui/unconditional_recursion.rs:18:9 | LL | self != other | ^^^^^^^^^^^^^ @@ -74,7 +74,7 @@ LL | self != other = help: to override `-D warnings` add `#[allow(clippy::unconditional_recursion)]` error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:22:5 + --> tests/ui/unconditional_recursion.rs:20:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -84,13 +84,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:25:9 + --> tests/ui/unconditional_recursion.rs:23:9 | LL | self == other | ^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:35:5 + --> tests/ui/unconditional_recursion.rs:33:5 | LL | / fn ne(&self, other: &Self) -> bool { LL | | @@ -99,13 +99,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:37:9 + --> tests/ui/unconditional_recursion.rs:35:9 | LL | self != &Foo2::B // no error here | ^^^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:39:5 + --> tests/ui/unconditional_recursion.rs:37:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -114,13 +114,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:41:9 + --> tests/ui/unconditional_recursion.rs:39:9 | LL | self == &Foo2::B // no error here | ^^^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:51:5 + --> tests/ui/unconditional_recursion.rs:49:5 | LL | / fn ne(&self, other: &Self) -> bool { LL | | @@ -130,13 +130,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:54:9 + --> tests/ui/unconditional_recursion.rs:52:9 | LL | self.ne(other) | ^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:56:5 + --> tests/ui/unconditional_recursion.rs:54:5 | LL | / fn eq(&self, other: &Self) -> bool { ... | @@ -144,13 +144,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:60:9 + --> tests/ui/unconditional_recursion.rs:58:9 | LL | self.eq(other) | ^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:102:5 + --> tests/ui/unconditional_recursion.rs:100:5 | LL | / fn ne(&self, other: &Self) -> bool { LL | | @@ -160,13 +160,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:105:9 + --> tests/ui/unconditional_recursion.rs:103:9 | LL | other != self | ^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:107:5 + --> tests/ui/unconditional_recursion.rs:105:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -176,13 +176,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:110:9 + --> tests/ui/unconditional_recursion.rs:108:9 | LL | other == self | ^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:118:5 + --> tests/ui/unconditional_recursion.rs:116:5 | LL | / fn ne(&self, other: &Self) -> bool { LL | | @@ -193,13 +193,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:121:9 + --> tests/ui/unconditional_recursion.rs:119:9 | LL | other != other | ^^^^^^^^^^^^^^ error: equal expressions as operands to `!=` - --> tests/ui/unconditional_recursion.rs:121:9 + --> tests/ui/unconditional_recursion.rs:119:9 | LL | other != other | ^^^^^^^^^^^^^^ @@ -207,7 +207,7 @@ LL | other != other = note: `#[deny(clippy::eq_op)]` on by default error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:124:5 + --> tests/ui/unconditional_recursion.rs:122:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -218,19 +218,19 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:127:9 + --> tests/ui/unconditional_recursion.rs:125:9 | LL | other == other | ^^^^^^^^^^^^^^ error: equal expressions as operands to `==` - --> tests/ui/unconditional_recursion.rs:127:9 + --> tests/ui/unconditional_recursion.rs:125:9 | LL | other == other | ^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:135:5 + --> tests/ui/unconditional_recursion.rs:133:5 | LL | / fn ne(&self, _other: &Self) -> bool { LL | | @@ -241,19 +241,19 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:138:9 + --> tests/ui/unconditional_recursion.rs:136:9 | LL | self != self | ^^^^^^^^^^^^ error: equal expressions as operands to `!=` - --> tests/ui/unconditional_recursion.rs:138:9 + --> tests/ui/unconditional_recursion.rs:136:9 | LL | self != self | ^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:141:5 + --> tests/ui/unconditional_recursion.rs:139:5 | LL | / fn eq(&self, _other: &Self) -> bool { LL | | @@ -264,19 +264,19 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:144:9 + --> tests/ui/unconditional_recursion.rs:142:9 | LL | self == self | ^^^^^^^^^^^^ error: equal expressions as operands to `==` - --> tests/ui/unconditional_recursion.rs:144:9 + --> tests/ui/unconditional_recursion.rs:142:9 | LL | self == self | ^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:171:13 + --> tests/ui/unconditional_recursion.rs:169:13 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -289,7 +289,7 @@ LL | impl_partial_eq!(S5); | -------------------- in this macro invocation | note: recursive call site - --> tests/ui/unconditional_recursion.rs:174:17 + --> tests/ui/unconditional_recursion.rs:172:17 | LL | self == other | ^^^^^^^^^^^^^ @@ -299,7 +299,7 @@ LL | impl_partial_eq!(S5); = note: this error originates in the macro `impl_partial_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:201:5 + --> tests/ui/unconditional_recursion.rs:199:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -311,13 +311,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:206:9 + --> tests/ui/unconditional_recursion.rs:204:9 | LL | mine == theirs | ^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:271:5 + --> tests/ui/unconditional_recursion.rs:269:5 | LL | / fn new() -> Self { LL | | @@ -327,13 +327,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:274:9 + --> tests/ui/unconditional_recursion.rs:272:9 | LL | Self::default() | ^^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:311:5 + --> tests/ui/unconditional_recursion.rs:309:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | @@ -345,13 +345,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:316:9 + --> tests/ui/unconditional_recursion.rs:314:9 | LL | mine.eq(theirs) | ^^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:383:5 + --> tests/ui/unconditional_recursion.rs:381:5 | LL | / fn from(f: BadFromTy1<'a>) -> Self { LL | | @@ -360,13 +360,13 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:385:9 + --> tests/ui/unconditional_recursion.rs:383:9 | LL | f.into() | ^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:393:5 + --> tests/ui/unconditional_recursion.rs:391:5 | LL | / fn from(f: BadFromTy2<'a>) -> Self { LL | | @@ -375,7 +375,7 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:395:9 + --> tests/ui/unconditional_recursion.rs:393:9 | LL | Into::into(f) | ^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unicode.fixed b/src/tools/clippy/tests/ui/unicode.fixed index 9234b440d9648..8fd25d1b48f5f 100644 --- a/src/tools/clippy/tests/ui/unicode.fixed +++ b/src/tools/clippy/tests/ui/unicode.fixed @@ -60,7 +60,4 @@ mod non_ascii_literal { } } -fn main() { - zero(); - canon(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/unicode.rs b/src/tools/clippy/tests/ui/unicode.rs index ada8bac8e0492..6447a704a3566 100644 --- a/src/tools/clippy/tests/ui/unicode.rs +++ b/src/tools/clippy/tests/ui/unicode.rs @@ -60,7 +60,4 @@ mod non_ascii_literal { } } -fn main() { - zero(); - canon(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.fixed b/src/tools/clippy/tests/ui/uninlined_format_args.fixed index 7b609d9163a9c..6e999a48595ca 100644 --- a/src/tools/clippy/tests/ui/uninlined_format_args.fixed +++ b/src/tools/clippy/tests/ui/uninlined_format_args.fixed @@ -238,9 +238,7 @@ fn tester(fn_arg: i32) { } } -fn main() { - tester(42); -} +fn main() {} #[clippy::msrv = "1.57"] fn _under_msrv() { diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.rs b/src/tools/clippy/tests/ui/uninlined_format_args.rs index 14e0b6caabc0e..58bbe41b97bfe 100644 --- a/src/tools/clippy/tests/ui/uninlined_format_args.rs +++ b/src/tools/clippy/tests/ui/uninlined_format_args.rs @@ -243,9 +243,7 @@ fn tester(fn_arg: i32) { } } -fn main() { - tester(42); -} +fn main() {} #[clippy::msrv = "1.57"] fn _under_msrv() { diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.stderr b/src/tools/clippy/tests/ui/uninlined_format_args.stderr index 7e62a095eadf7..45994fdc9588f 100644 --- a/src/tools/clippy/tests/ui/uninlined_format_args.stderr +++ b/src/tools/clippy/tests/ui/uninlined_format_args.stderr @@ -836,7 +836,7 @@ LL + panic!("p3 {local_i32}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:259:5 + --> tests/ui/uninlined_format_args.rs:257:5 | LL | println!("expand='{}'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -848,7 +848,7 @@ LL + println!("expand='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:362:5 + --> tests/ui/uninlined_format_args.rs:360:5 | LL | usr_println!(true, "val='{}'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -860,7 +860,7 @@ LL + usr_println!(true, "val='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:364:5 + --> tests/ui/uninlined_format_args.rs:362:5 | LL | usr_println!(true, "{}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -872,7 +872,7 @@ LL + usr_println!(true, "{local_i32}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:366:5 + --> tests/ui/uninlined_format_args.rs:364:5 | LL | usr_println!(true, "{:#010x}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -884,7 +884,7 @@ LL + usr_println!(true, "{local_i32:#010x}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:368:5 + --> tests/ui/uninlined_format_args.rs:366:5 | LL | usr_println!(true, "{:.1}", local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unit_arg.rs b/src/tools/clippy/tests/ui/unit_arg.rs index 4208efad6774d..3cba0735b3623 100644 --- a/src/tools/clippy/tests/ui/unit_arg.rs +++ b/src/tools/clippy/tests/ui/unit_arg.rs @@ -147,10 +147,7 @@ fn proc_macro() { with_span!(span taking_multiple_units(unsafe { (); }, 'x: loop { break 'x (); })); } -fn main() { - bad(); - ok(); -} +fn main() {} fn issue14857() { let fn_take_unit = |_: ()| {}; diff --git a/src/tools/clippy/tests/ui/unit_arg.stderr b/src/tools/clippy/tests/ui/unit_arg.stderr index eb7c56c45b595..ed13108631574 100644 --- a/src/tools/clippy/tests/ui/unit_arg.stderr +++ b/src/tools/clippy/tests/ui/unit_arg.stderr @@ -200,19 +200,19 @@ LL + Some(()) | error: passing a unit value to a function - --> tests/ui/unit_arg.rs:171:5 + --> tests/ui/unit_arg.rs:168:5 | LL | fn_take_unit(mac!(def)); | ^^^^^^^^^^^^^^^^^^^^^^^ error: passing a unit value to a function - --> tests/ui/unit_arg.rs:173:5 + --> tests/ui/unit_arg.rs:170:5 | LL | fn_take_unit(mac!(func Default::default)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: passing a unit value to a function - --> tests/ui/unit_arg.rs:175:5 + --> tests/ui/unit_arg.rs:172:5 | LL | fn_take_unit(mac!(nonempty_block Default::default())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unit_arg_fixable.fixed b/src/tools/clippy/tests/ui/unit_arg_fixable.fixed index 03353a14081b2..3bbc62ca0bca7 100644 --- a/src/tools/clippy/tests/ui/unit_arg_fixable.fixed +++ b/src/tools/clippy/tests/ui/unit_arg_fixable.fixed @@ -29,9 +29,7 @@ fn bad() { fn taking_two_units(a: (), b: ()) {} fn taking_three_units(a: (), b: (), c: ()) {} -fn main() { - bad(); -} +fn main() {} fn issue14857() { let fn_take_unit = |_: ()| {}; diff --git a/src/tools/clippy/tests/ui/unit_arg_fixable.rs b/src/tools/clippy/tests/ui/unit_arg_fixable.rs index 03fd96efdf901..12d6cbcf61d92 100644 --- a/src/tools/clippy/tests/ui/unit_arg_fixable.rs +++ b/src/tools/clippy/tests/ui/unit_arg_fixable.rs @@ -26,9 +26,7 @@ fn bad() { fn taking_two_units(a: (), b: ()) {} fn taking_three_units(a: (), b: (), c: ()) {} -fn main() { - bad(); -} +fn main() {} fn issue14857() { let fn_take_unit = |_: ()| {}; diff --git a/src/tools/clippy/tests/ui/unit_arg_fixable.stderr b/src/tools/clippy/tests/ui/unit_arg_fixable.stderr index 0e348c81c0d43..9f6bc671bf55b 100644 --- a/src/tools/clippy/tests/ui/unit_arg_fixable.stderr +++ b/src/tools/clippy/tests/ui/unit_arg_fixable.stderr @@ -50,7 +50,7 @@ LL ~ taking_three_units((), (), ()); | error: passing a unit value to a function - --> tests/ui/unit_arg_fixable.rs:35:5 + --> tests/ui/unit_arg_fixable.rs:33:5 | LL | fn_take_unit(Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -62,7 +62,7 @@ LL + fn_take_unit(()); | error: passing a unit value to a function - --> tests/ui/unit_arg_fixable.rs:49:5 + --> tests/ui/unit_arg_fixable.rs:47:5 | LL | fn_take_unit(another_mac!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -74,7 +74,7 @@ LL ~ fn_take_unit(()); | error: passing a unit value to a function - --> tests/ui/unit_arg_fixable.rs:51:5 + --> tests/ui/unit_arg_fixable.rs:49:5 | LL | fn_take_unit(another_mac!(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -86,7 +86,7 @@ LL ~ fn_take_unit(()); | error: passing a unit value to a function - --> tests/ui/unit_arg_fixable.rs:60:5 + --> tests/ui/unit_arg_fixable.rs:58:5 | LL | fn_take_unit(mac!(nondef Default::default())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -98,7 +98,7 @@ LL + fn_take_unit(mac!(nondef ())); | error: passing a unit value to a function - --> tests/ui/unit_arg_fixable.rs:62:5 + --> tests/ui/unit_arg_fixable.rs:60:5 | LL | fn_take_unit(mac!(empty_block)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -110,7 +110,7 @@ LL ~ fn_take_unit(()); | error: passing a unit value to a function - --> tests/ui/unit_arg_fixable.rs:69:5 + --> tests/ui/unit_arg_fixable.rs:67:5 | LL | fn_take_unit(def()); | ^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.fixed b/src/tools/clippy/tests/ui/unnecessary_cast.fixed index 91ff4b9ee7713..c6e9bc3cba077 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_cast.fixed @@ -133,12 +133,13 @@ fn main() { aaa(); //~^ unnecessary_cast let x = aaa(); - aaa(); + x; + //~^ unnecessary_cast + bbb(); //~^ unnecessary_cast - // Will not lint currently. - bbb() as u32; let x = bbb(); - bbb() as u32; + x; + //~^ unnecessary_cast let i8_ptr: *const i8 = &1; let u8_ptr: *const u8 = &1; diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.rs b/src/tools/clippy/tests/ui/unnecessary_cast.rs index 5444a914db167..6936a23d42861 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.rs +++ b/src/tools/clippy/tests/ui/unnecessary_cast.rs @@ -133,12 +133,13 @@ fn main() { aaa() as u32; //~^ unnecessary_cast let x = aaa(); - aaa() as u32; + x as u32; //~^ unnecessary_cast - // Will not lint currently. bbb() as u32; + //~^ unnecessary_cast let x = bbb(); - bbb() as u32; + x as u32; + //~^ unnecessary_cast let i8_ptr: *const i8 = &1; let u8_ptr: *const u8 = &1; diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.stderr b/src/tools/clippy/tests/ui/unnecessary_cast.stderr index 3e3c5eb81c105..e4f4309ea7163 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_cast.stderr @@ -100,170 +100,182 @@ LL | aaa() as u32; error: casting to the same type is unnecessary (`u32` -> `u32`) --> tests/ui/unnecessary_cast.rs:136:5 | -LL | aaa() as u32; - | ^^^^^^^^^^^^ help: try: `aaa()` +LL | x as u32; + | ^^^^^^^^ help: try: `x` + +error: casting to the same type is unnecessary (`u32` -> `u32`) + --> tests/ui/unnecessary_cast.rs:138:5 + | +LL | bbb() as u32; + | ^^^^^^^^^^^^ help: try: `bbb()` + +error: casting to the same type is unnecessary (`u32` -> `u32`) + --> tests/ui/unnecessary_cast.rs:141:5 + | +LL | x as u32; + | ^^^^^^^^ help: try: `x` error: casting integer literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:173:9 + --> tests/ui/unnecessary_cast.rs:174:9 | LL | 100 as f32; | ^^^^^^^^^^ help: try: `100_f32` error: casting integer literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:175:9 + --> tests/ui/unnecessary_cast.rs:176:9 | LL | 100 as f64; | ^^^^^^^^^^ help: try: `100_f64` error: casting integer literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:177:9 + --> tests/ui/unnecessary_cast.rs:178:9 | LL | 100_i32 as f64; | ^^^^^^^^^^^^^^ help: try: `100_f64` error: casting integer literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:179:17 + --> tests/ui/unnecessary_cast.rs:180:17 | LL | let _ = -100 as f32; | ^^^^^^^^^^^ help: try: `-100_f32` error: casting integer literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:181:17 + --> tests/ui/unnecessary_cast.rs:182:17 | LL | let _ = -100 as f64; | ^^^^^^^^^^^ help: try: `-100_f64` error: casting integer literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:183:17 + --> tests/ui/unnecessary_cast.rs:184:17 | LL | let _ = -100_i32 as f64; | ^^^^^^^^^^^^^^^ help: try: `-100_f64` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:185:9 + --> tests/ui/unnecessary_cast.rs:186:9 | LL | 100. as f32; | ^^^^^^^^^^^ help: try: `100_f32` error: casting float literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:187:9 + --> tests/ui/unnecessary_cast.rs:188:9 | LL | 100. as f64; | ^^^^^^^^^^^ help: try: `100_f64` error: casting integer literal to `u32` is unnecessary - --> tests/ui/unnecessary_cast.rs:200:9 + --> tests/ui/unnecessary_cast.rs:201:9 | LL | 1 as u32; | ^^^^^^^^ help: try: `1_u32` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:202:9 + --> tests/ui/unnecessary_cast.rs:203:9 | LL | 0x10 as i32; | ^^^^^^^^^^^ help: try: `0x10_i32` error: casting integer literal to `usize` is unnecessary - --> tests/ui/unnecessary_cast.rs:204:9 + --> tests/ui/unnecessary_cast.rs:205:9 | LL | 0b10 as usize; | ^^^^^^^^^^^^^ help: try: `0b10_usize` error: casting integer literal to `u16` is unnecessary - --> tests/ui/unnecessary_cast.rs:206:9 + --> tests/ui/unnecessary_cast.rs:207:9 | LL | 0o73 as u16; | ^^^^^^^^^^^ help: try: `0o73_u16` error: casting integer literal to `u32` is unnecessary - --> tests/ui/unnecessary_cast.rs:208:9 + --> tests/ui/unnecessary_cast.rs:209:9 | LL | 1_000_000_000 as u32; | ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32` error: casting float literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:211:9 + --> tests/ui/unnecessary_cast.rs:212:9 | LL | 1.0 as f64; | ^^^^^^^^^^ help: try: `1.0_f64` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:213:9 + --> tests/ui/unnecessary_cast.rs:214:9 | LL | 0.5 as f32; | ^^^^^^^^^^ help: try: `0.5_f32` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:218:17 + --> tests/ui/unnecessary_cast.rs:219:17 | LL | let _ = -1 as i32; | ^^^^^^^^^ help: try: `-1_i32` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:220:17 + --> tests/ui/unnecessary_cast.rs:221:17 | LL | let _ = -1.0 as f32; | ^^^^^^^^^^^ help: try: `-1.0_f32` error: casting to the same type is unnecessary (`i32` -> `i32`) - --> tests/ui/unnecessary_cast.rs:227:18 + --> tests/ui/unnecessary_cast.rs:228:18 | LL | let _ = &(x as i32); | ^^^^^^^^^^ help: try: `{ x }` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:234:22 + --> tests/ui/unnecessary_cast.rs:235:22 | LL | let _: i32 = -(1) as i32; | ^^^^^^^^^^^ help: try: `-1_i32` error: casting integer literal to `i64` is unnecessary - --> tests/ui/unnecessary_cast.rs:237:22 + --> tests/ui/unnecessary_cast.rs:238:22 | LL | let _: i64 = -(1) as i64; | ^^^^^^^^^^^ help: try: `-1_i64` error: casting float literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:245:22 + --> tests/ui/unnecessary_cast.rs:246:22 | LL | let _: f64 = (-8.0 as f64).exp(); | ^^^^^^^^^^^^^ help: try: `(-8.0_f64)` error: casting float literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:248:23 + --> tests/ui/unnecessary_cast.rs:249:23 | LL | let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior | ^^^^^^^^^^^^ help: try: `8.0_f64` error: casting to the same type is unnecessary (`f32` -> `f32`) - --> tests/ui/unnecessary_cast.rs:258:20 + --> tests/ui/unnecessary_cast.rs:259:20 | LL | let _num = foo() as f32; | ^^^^^^^^^^^^ help: try: `foo()` error: casting to the same type is unnecessary (`usize` -> `usize`) - --> tests/ui/unnecessary_cast.rs:269:9 + --> tests/ui/unnecessary_cast.rs:270:9 | LL | (*x as usize).pow(2) | ^^^^^^^^^^^^^ help: try: `(*x)` error: casting to the same type is unnecessary (`usize` -> `usize`) - --> tests/ui/unnecessary_cast.rs:277:31 + --> tests/ui/unnecessary_cast.rs:278:31 | LL | assert_eq!(vec.len(), x as usize); | ^^^^^^^^^^ help: try: `x` error: casting to the same type is unnecessary (`i64` -> `i64`) - --> tests/ui/unnecessary_cast.rs:280:17 + --> tests/ui/unnecessary_cast.rs:281:17 | LL | let _ = (5i32 as i64 as i64).abs(); | ^^^^^^^^^^^^^^^^^^^^ help: try: `(5i32 as i64)` error: casting to the same type is unnecessary (`i64` -> `i64`) - --> tests/ui/unnecessary_cast.rs:283:17 + --> tests/ui/unnecessary_cast.rs:284:17 | LL | let _ = 5i32 as i64 as i64; | ^^^^^^^^^^^^^^^^^^ help: try: `5i32 as i64` -error: aborting due to 44 previous errors +error: aborting due to 46 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_fold.fixed b/src/tools/clippy/tests/ui/unnecessary_fold.fixed index d51359349cb9e..a8370ed03b746 100644 --- a/src/tools/clippy/tests/ui/unnecessary_fold.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_fold.fixed @@ -88,16 +88,6 @@ fn unnecessary_fold_should_ignore() { let _: i32 = (0..3).fold(0, FakeAdd::add); let _: i32 = (0..3).fold(1, FakeMul::mul); - // We only match against an accumulator on the left - // hand side. We could lint for .sum and .product when - // it's on the right, but don't for now (and this wouldn't - // be valid if we extended the lint to cover arbitrary numeric - // types). - let _ = (0..3).fold(false, |acc, x| x > 2 || acc); - let _ = (0..3).fold(true, |acc, x| x > 2 && acc); - let _ = (0..3).fold(0, |acc, x| x + acc); - let _ = (0..3).fold(1, |acc, x| x * acc); - let _ = [(0..2), (0..3)].iter().fold(0, |a, b| a + b.len()); let _ = [(0..2), (0..3)].iter().fold(1, |a, b| a * b.len()); } @@ -178,6 +168,26 @@ fn issue10000() { } } +fn issue16581() { + let _ = (2..=3).product::(); + //~^ unnecessary_fold + let _ = (1..=3).sum::(); + //~^ unnecessary_fold + let _ = (2..=3).product::(); + //~^ unnecessary_fold + let _ = (1..=3).sum::(); + //~^ unnecessary_fold + + let _ = (0..3).any(|x| x > 2); + //~^ unnecessary_fold + let _ = (0..3).all(|x| x > 2); + //~^ unnecessary_fold + let _ = (0..3).sum::(); + //~^ unnecessary_fold + let _ = (0..3).product::(); + //~^ unnecessary_fold +} + fn wrongly_unmangled_macros() { macro_rules! test_expr { ($e:expr) => { diff --git a/src/tools/clippy/tests/ui/unnecessary_fold.rs b/src/tools/clippy/tests/ui/unnecessary_fold.rs index c6eb7157ab129..f495da6e720ba 100644 --- a/src/tools/clippy/tests/ui/unnecessary_fold.rs +++ b/src/tools/clippy/tests/ui/unnecessary_fold.rs @@ -88,16 +88,6 @@ fn unnecessary_fold_should_ignore() { let _: i32 = (0..3).fold(0, FakeAdd::add); let _: i32 = (0..3).fold(1, FakeMul::mul); - // We only match against an accumulator on the left - // hand side. We could lint for .sum and .product when - // it's on the right, but don't for now (and this wouldn't - // be valid if we extended the lint to cover arbitrary numeric - // types). - let _ = (0..3).fold(false, |acc, x| x > 2 || acc); - let _ = (0..3).fold(true, |acc, x| x > 2 && acc); - let _ = (0..3).fold(0, |acc, x| x + acc); - let _ = (0..3).fold(1, |acc, x| x * acc); - let _ = [(0..2), (0..3)].iter().fold(0, |a, b| a + b.len()); let _ = [(0..2), (0..3)].iter().fold(1, |a, b| a * b.len()); } @@ -178,6 +168,26 @@ fn issue10000() { } } +fn issue16581() { + let _ = (2..=3).fold(1, |a, b| a * b); + //~^ unnecessary_fold + let _ = (1..=3).fold(0, |a, b| a + b); + //~^ unnecessary_fold + let _ = (2..=3).fold(1, |b, a| a * b); + //~^ unnecessary_fold + let _ = (1..=3).fold(0, |b, a| a + b); + //~^ unnecessary_fold + + let _ = (0..3).fold(false, |acc, x| x > 2 || acc); + //~^ unnecessary_fold + let _ = (0..3).fold(true, |acc, x| x > 2 && acc); + //~^ unnecessary_fold + let _ = (0..3).fold(0, |acc, x| x + acc); + //~^ unnecessary_fold + let _ = (0..3).fold(1, |acc, x| x * acc); + //~^ unnecessary_fold +} + fn wrongly_unmangled_macros() { macro_rules! test_expr { ($e:expr) => { diff --git a/src/tools/clippy/tests/ui/unnecessary_fold.stderr b/src/tools/clippy/tests/ui/unnecessary_fold.stderr index 560427a681a98..266ced07eb827 100644 --- a/src/tools/clippy/tests/ui/unnecessary_fold.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_fold.stderr @@ -70,7 +70,7 @@ LL | let _: bool = (0..3).map(|x| 2 * x).fold(false, |acc, x| acc || x > 2); = note: the `any` method is short circuiting and may change the program semantics if the iterator has side effects error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:110:10 + --> tests/ui/unnecessary_fold.rs:100:10 | LL | .fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` @@ -78,138 +78,190 @@ LL | .fold(false, |acc, x| acc || x > 2); = note: the `any` method is short circuiting and may change the program semantics if the iterator has side effects error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:123:33 + --> tests/ui/unnecessary_fold.rs:113:33 | LL | assert_eq!(map.values().fold(0, |x, y| x + y), 0); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:127:30 + --> tests/ui/unnecessary_fold.rs:117:30 | LL | let _ = map.values().fold(0, |x, y| x + y); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:129:30 + --> tests/ui/unnecessary_fold.rs:119:30 | LL | let _ = map.values().fold(0, Add::add); | ^^^^^^^^^^^^^^^^^ help: try: `sum::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:131:30 + --> tests/ui/unnecessary_fold.rs:121:30 | LL | let _ = map.values().fold(1, |x, y| x * y); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:133:30 + --> tests/ui/unnecessary_fold.rs:123:30 | LL | let _ = map.values().fold(1, Mul::mul); | ^^^^^^^^^^^^^^^^^ help: try: `product::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:135:35 + --> tests/ui/unnecessary_fold.rs:125:35 | LL | let _: i32 = map.values().fold(0, |x, y| x + y); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:137:35 + --> tests/ui/unnecessary_fold.rs:127:35 | LL | let _: i32 = map.values().fold(0, Add::add); | ^^^^^^^^^^^^^^^^^ help: try: `sum()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:139:35 + --> tests/ui/unnecessary_fold.rs:129:35 | LL | let _: i32 = map.values().fold(1, |x, y| x * y); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:141:35 + --> tests/ui/unnecessary_fold.rs:131:35 | LL | let _: i32 = map.values().fold(1, Mul::mul); | ^^^^^^^^^^^^^^^^^ help: try: `product()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:143:31 + --> tests/ui/unnecessary_fold.rs:133:31 | LL | anything(map.values().fold(0, |x, y| x + y)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:145:31 + --> tests/ui/unnecessary_fold.rs:135:31 | LL | anything(map.values().fold(0, Add::add)); | ^^^^^^^^^^^^^^^^^ help: try: `sum::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:147:31 + --> tests/ui/unnecessary_fold.rs:137:31 | LL | anything(map.values().fold(1, |x, y| x * y)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:149:31 + --> tests/ui/unnecessary_fold.rs:139:31 | LL | anything(map.values().fold(1, Mul::mul)); | ^^^^^^^^^^^^^^^^^ help: try: `product::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:151:26 + --> tests/ui/unnecessary_fold.rs:141:26 | LL | num(map.values().fold(0, |x, y| x + y)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:153:26 + --> tests/ui/unnecessary_fold.rs:143:26 | LL | num(map.values().fold(0, Add::add)); | ^^^^^^^^^^^^^^^^^ help: try: `sum()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:155:26 + --> tests/ui/unnecessary_fold.rs:145:26 | LL | num(map.values().fold(1, |x, y| x * y)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:157:26 + --> tests/ui/unnecessary_fold.rs:147:26 | LL | num(map.values().fold(1, Mul::mul)); | ^^^^^^^^^^^^^^^^^ help: try: `product()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:164:16 + --> tests/ui/unnecessary_fold.rs:154:16 | LL | (0..3).fold(0, |acc, x| acc + x) | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:168:16 + --> tests/ui/unnecessary_fold.rs:158:16 | LL | (0..3).fold(1, |acc, x| acc * x) | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `product()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:172:16 + --> tests/ui/unnecessary_fold.rs:162:16 | LL | (0..3).fold(0, |acc, x| acc + x) | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:176:16 + --> tests/ui/unnecessary_fold.rs:166:16 | LL | (0..3).fold(1, |acc, x| acc * x) | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:188:20 + --> tests/ui/unnecessary_fold.rs:172:21 + | +LL | let _ = (2..=3).fold(1, |a, b| a * b); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:174:21 + | +LL | let _ = (1..=3).fold(0, |a, b| a + b); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:176:21 + | +LL | let _ = (2..=3).fold(1, |b, a| a * b); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:178:21 + | +LL | let _ = (1..=3).fold(0, |b, a| a + b); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:181:20 + | +LL | let _ = (0..3).fold(false, |acc, x| x > 2 || acc); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` + | + = note: the `any` method is short circuiting and may change the program semantics if the iterator has side effects + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:183:20 + | +LL | let _ = (0..3).fold(true, |acc, x| x > 2 && acc); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `all(|x| x > 2)` + | + = note: the `all` method is short circuiting and may change the program semantics if the iterator has side effects + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:185:20 + | +LL | let _ = (0..3).fold(0, |acc, x| x + acc); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:187:20 + | +LL | let _ = (0..3).fold(1, |acc, x| x * acc); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` + +error: this `.fold` can be written more succinctly using another method + --> tests/ui/unnecessary_fold.rs:198:20 | LL | let _ = (0..3).fold(false, |acc: bool, x| acc || test_expr!(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| test_expr!(x))` | = note: the `any` method is short circuiting and may change the program semantics if the iterator has side effects -error: aborting due to 33 previous errors +error: aborting due to 41 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed index 877f4ad41c7ef..05ffdeb1dcc59 100644 --- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed @@ -152,12 +152,4 @@ fn unwrap_unchecked() { //~^ unnecessary_literal_unwrap } -fn main() { - unwrap_option_some(); - unwrap_option_none(); - unwrap_result_ok(); - unwrap_result_err(); - unwrap_methods_option(); - unwrap_methods_result(); - unwrap_unchecked(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs index c0a35ae78a71d..5efefb24530b9 100644 --- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs +++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs @@ -152,12 +152,4 @@ fn unwrap_unchecked() { //~^ unnecessary_literal_unwrap } -fn main() { - unwrap_option_some(); - unwrap_option_none(); - unwrap_result_ok(); - unwrap_result_err(); - unwrap_methods_option(); - unwrap_methods_result(); - unwrap_unchecked(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.rs b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.rs index b6cba4e6a5685..2680d0a6697be 100644 --- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.rs +++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.rs @@ -191,16 +191,4 @@ fn unwrap_methods_result_context() { //~^ unnecessary_literal_unwrap } -fn main() { - unwrap_option_some(); - unwrap_option_some_context(); - unwrap_option_none(); - unwrap_result_ok(); - unwrap_result_ok_context(); - unwrap_result_err(); - unwrap_result_err_context(); - unwrap_methods_option(); - unwrap_methods_option_context(); - unwrap_methods_result(); - unwrap_methods_result_context(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/unnecessary_min_or_max.fixed b/src/tools/clippy/tests/ui/unnecessary_min_or_max.fixed index 2650cae5baf46..e2e1700e28b99 100644 --- a/src/tools/clippy/tests/ui/unnecessary_min_or_max.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_min_or_max.fixed @@ -77,6 +77,32 @@ fn main() { let _ = (X + 1).min(12); let _ = 12.min(X - 1); let _ = 12.max(X - 1); + + let n: usize = 42; + + let _ = 0; + //~^ unnecessary_min_or_max + + let _ = 0usize; + //~^ unnecessary_min_or_max + + let _ = (0usize); + //~^ unnecessary_min_or_max + + let _ = usize::MIN; + //~^ unnecessary_min_or_max + + let _ = usize::MAX; + //~^ unnecessary_min_or_max + + let _ = (usize::MAX); + //~^ unnecessary_min_or_max + + let _ = !0usize; + //~^ unnecessary_min_or_max + + let _ = n; + //~^ unnecessary_min_or_max } fn random_u32() -> u32 { // random number generator diff --git a/src/tools/clippy/tests/ui/unnecessary_min_or_max.rs b/src/tools/clippy/tests/ui/unnecessary_min_or_max.rs index 2f3c480b3d150..dd71ee2080305 100644 --- a/src/tools/clippy/tests/ui/unnecessary_min_or_max.rs +++ b/src/tools/clippy/tests/ui/unnecessary_min_or_max.rs @@ -77,6 +77,32 @@ fn main() { let _ = (X + 1).min(12); let _ = 12.min(X - 1); let _ = 12.max(X - 1); + + let n: usize = 42; + + let _ = n.min(0); + //~^ unnecessary_min_or_max + + let _ = n.min(0usize); + //~^ unnecessary_min_or_max + + let _ = (0usize).min(n); + //~^ unnecessary_min_or_max + + let _ = n.min(usize::MIN); + //~^ unnecessary_min_or_max + + let _ = n.max(usize::MAX); + //~^ unnecessary_min_or_max + + let _ = (usize::MAX).max(n); + //~^ unnecessary_min_or_max + + let _ = n.max(!0usize); + //~^ unnecessary_min_or_max + + let _ = n.max(0); + //~^ unnecessary_min_or_max } fn random_u32() -> u32 { // random number generator diff --git a/src/tools/clippy/tests/ui/unnecessary_min_or_max.stderr b/src/tools/clippy/tests/ui/unnecessary_min_or_max.stderr index dfe6910dfa5cb..b391d21d3bf43 100644 --- a/src/tools/clippy/tests/ui/unnecessary_min_or_max.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_min_or_max.stderr @@ -103,5 +103,53 @@ error: `x` is never smaller than `i32::MIN - 0` and has therefore no effect LL | let _ = x.min(i32::MIN - 0); | ^^^^^^^^^^^^^^^^^^^ help: try: `i32::MIN - 0` -error: aborting due to 17 previous errors +error: `n` is never smaller than `0` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:83:13 + | +LL | let _ = n.min(0); + | ^^^^^^^^ help: try: `0` + +error: `n` is never smaller than `0usize` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:86:13 + | +LL | let _ = n.min(0usize); + | ^^^^^^^^^^^^^ help: try: `0usize` + +error: `(0usize)` is never greater than `n` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:89:13 + | +LL | let _ = (0usize).min(n); + | ^^^^^^^^^^^^^^^ help: try: `(0usize)` + +error: `n` is never smaller than `usize::MIN` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:92:13 + | +LL | let _ = n.min(usize::MIN); + | ^^^^^^^^^^^^^^^^^ help: try: `usize::MIN` + +error: `n` is never greater than `usize::MAX` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:95:13 + | +LL | let _ = n.max(usize::MAX); + | ^^^^^^^^^^^^^^^^^ help: try: `usize::MAX` + +error: `(usize::MAX)` is never smaller than `n` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:98:13 + | +LL | let _ = (usize::MAX).max(n); + | ^^^^^^^^^^^^^^^^^^^ help: try: `(usize::MAX)` + +error: `n` is never greater than `!0usize` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:101:13 + | +LL | let _ = n.max(!0usize); + | ^^^^^^^^^^^^^^ help: try: `!0usize` + +error: `n` is never smaller than `0` and has therefore no effect + --> tests/ui/unnecessary_min_or_max.rs:104:13 + | +LL | let _ = n.max(0); + | ^^^^^^^^ help: try: `n` + +error: aborting due to 25 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed b/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed index 6870470e74c5a..317140eacc785 100644 --- a/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed @@ -106,11 +106,7 @@ mod issue_6001 { } } -fn main() { - unnecessary_sort_by(); - issue_5754::test(); - issue_6001::test(); -} +fn main() {} fn issue16405() { let mut v: Vec<(i32, &str)> = vec![(1, "foo"), (2, "bar")]; diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.rs b/src/tools/clippy/tests/ui/unnecessary_sort_by.rs index d95306176817d..a31cf29679993 100644 --- a/src/tools/clippy/tests/ui/unnecessary_sort_by.rs +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.rs @@ -106,11 +106,7 @@ mod issue_6001 { } } -fn main() { - unnecessary_sort_by(); - issue_5754::test(); - issue_6001::test(); -} +fn main() {} fn issue16405() { let mut v: Vec<(i32, &str)> = vec![(1, "foo"), (2, "bar")]; diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr b/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr index cc545d604ff3b..56d4831eb70aa 100644 --- a/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr @@ -145,7 +145,7 @@ LL + args.sort_unstable_by_key(|b| std::cmp::Reverse(b.name())); | error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by.rs:118:5 + --> tests/ui/unnecessary_sort_by.rs:114:5 | LL | v.sort_by(|a, b| a.0.cmp(&b.0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL + v.sort_by_key(|a| a.0); | error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by.rs:136:5 + --> tests/ui/unnecessary_sort_by.rs:132:5 | LL | items.sort_by(|item1, item2| item1.key.cmp(&item2.key)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL + items.sort_by_key(|item1| item1.key); | error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by.rs:141:5 + --> tests/ui/unnecessary_sort_by.rs:137:5 | LL | items.sort_by(|item1, item2| item1.value.clone().cmp(&item2.value.clone())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + items.sort_by_key(|item1| item1.value.clone()); | error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by.rs:147:5 + --> tests/ui/unnecessary_sort_by.rs:143:5 | LL | v.sort_by(|(_, s1), (_, s2)| s1.cmp(s2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -193,7 +193,7 @@ LL + v.sort_by_key(|(_, s1)| *s1); | error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by.rs:154:5 + --> tests/ui/unnecessary_sort_by.rs:150:5 | LL | v.sort_by(|Foo { bar: b1 }, Foo { bar: b2 }| b1.cmp(b2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -205,7 +205,7 @@ LL + v.sort_by_key(|Foo { bar: b1 }| *b1); | error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by.rs:159:5 + --> tests/ui/unnecessary_sort_by.rs:155:5 | LL | v.sort_by(|Baz(b1), Baz(b2)| b1.cmp(b2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -217,7 +217,7 @@ LL + v.sort_by_key(|Baz(b1)| *b1); | error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by.rs:162:5 + --> tests/ui/unnecessary_sort_by.rs:158:5 | LL | v.sort_by(|&Baz(b1), &Baz(b2)| b1.cmp(&b2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -229,7 +229,7 @@ LL + v.sort_by_key(|&Baz(b1)| b1); | error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by.rs:166:5 + --> tests/ui/unnecessary_sort_by.rs:162:5 | LL | v.sort_by(|&&b1, &&b2| b1.cmp(&b2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,7 +241,7 @@ LL + v.sort_by_key(|&&b1| b1); | error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by.rs:170:5 + --> tests/ui/unnecessary_sort_by.rs:166:5 | LL | v.sort_by(|[a1, b1], [a2, b2]| a1.cmp(a2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -253,7 +253,7 @@ LL + v.sort_by_key(|[a1, b1]| *a1); | error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by.rs:173:5 + --> tests/ui/unnecessary_sort_by.rs:169:5 | LL | v.sort_by(|[a1, b1], [a2, b2]| (a1 - b1).cmp(&(a2 - b2))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unnecessary_trailing_comma.fixed b/src/tools/clippy/tests/ui/unnecessary_trailing_comma.fixed new file mode 100644 index 0000000000000..499d9ee1ca235 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_trailing_comma.fixed @@ -0,0 +1,86 @@ +// run-rustfix +#![warn(clippy::unnecessary_trailing_comma)] + +fn main() {} + +// fmt breaks - https://github.com/rust-lang/rustfmt/issues/6797 +#[rustfmt::skip] +fn simple() { + println!["Foo(,)"]; + println!("Foo"); //~ unnecessary_trailing_comma + println!{"Foo"}; //~ unnecessary_trailing_comma + println!["Foo"]; //~ unnecessary_trailing_comma + println!("Foo={}", 1); //~ unnecessary_trailing_comma + println!(concat!("b", "o", "o")); //~ unnecessary_trailing_comma + println!("Foo(,)"); //~ unnecessary_trailing_comma + println!("Foo[,]"); //~ unnecessary_trailing_comma + println!["Foo(,)"]; //~ unnecessary_trailing_comma + println!["Foo[,]"]; //~ unnecessary_trailing_comma + println!["Foo{{,}}"]; //~ unnecessary_trailing_comma + println!{"Foo{{,}}"}; //~ unnecessary_trailing_comma + println!{"Foo(,)"}; //~ unnecessary_trailing_comma + println!{"Foo[,]"}; //~ unnecessary_trailing_comma + println!["Foo(,"]; //~ unnecessary_trailing_comma + println!["Foo[,"]; //~ unnecessary_trailing_comma + println!["Foo{{,}}"]; //~ unnecessary_trailing_comma + println!{"Foo{{,}}"}; //~ unnecessary_trailing_comma + println!{"Foo(,"}; //~ unnecessary_trailing_comma + println!{"Foo[,"}; //~ unnecessary_trailing_comma + + // This should eventually work, but requires more work + println!(concat!("Foo", "=", "{}"), 1,); + println!("No params", /*"a,){ */); + println!("No params" /* "a,){*/, /*"a,){ */); + + // No trailing comma - no lint + println!("{}", 1); + println!(concat!("b", "o", "o")); + println!(concat!("Foo", "=", "{}"), 1); + + println!("Foo" ); + println!{"Foo" }; + println!["Foo" ]; + println!("Foo={}", 1); + println!(concat!("b", "o", "o")); + println!("Foo(,)"); + println!("Foo[,]"); + println!["Foo(,)"]; + println!["Foo[,]"]; + println!["Foo{{,}}"]; + println!{"Foo{{,}}"}; + println!{"Foo(,)"}; + println!{"Foo[,]"}; + println!["Foo(,"]; + println!["Foo[,"]; + println!["Foo{{,}}"]; + println!{"Foo{{,}}"}; + println!{"Foo(,"}; + println!{"Foo[,"}; + + // Multi-line macro - must NOT lint (single-line only) + println!( + "very long string to prevent fmt from making it into a single line: {}", + 1, + ); + + print!("{}" + , 1 + ,); +} + +// The macro invocation itself should never be fixed +// The call to println! on the other hand might be ok to suggest in the future + +macro_rules! from_macro { + (0,) => { + println!("Foo",); + }; + (1,) => { + println!("Foo={}", 1,); + }; +} + +fn from_macro() { + from_macro!(0,); + from_macro!(1,); +} diff --git a/src/tools/clippy/tests/ui/unnecessary_trailing_comma.rs b/src/tools/clippy/tests/ui/unnecessary_trailing_comma.rs new file mode 100644 index 0000000000000..15dea27b887b6 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_trailing_comma.rs @@ -0,0 +1,86 @@ +// run-rustfix +#![warn(clippy::unnecessary_trailing_comma)] + +fn main() {} + +// fmt breaks - https://github.com/rust-lang/rustfmt/issues/6797 +#[rustfmt::skip] +fn simple() { + println!["Foo(,)"]; + println!("Foo" , ); //~ unnecessary_trailing_comma + println!{"Foo" , }; //~ unnecessary_trailing_comma + println!["Foo" , ]; //~ unnecessary_trailing_comma + println!("Foo={}", 1 , ); //~ unnecessary_trailing_comma + println!(concat!("b", "o", "o") , ); //~ unnecessary_trailing_comma + println!("Foo(,)",); //~ unnecessary_trailing_comma + println!("Foo[,]" , ); //~ unnecessary_trailing_comma + println!["Foo(,)", ]; //~ unnecessary_trailing_comma + println!["Foo[,]", ]; //~ unnecessary_trailing_comma + println!["Foo{{,}}", ]; //~ unnecessary_trailing_comma + println!{"Foo{{,}}", }; //~ unnecessary_trailing_comma + println!{"Foo(,)", }; //~ unnecessary_trailing_comma + println!{"Foo[,]", }; //~ unnecessary_trailing_comma + println!["Foo(,", ]; //~ unnecessary_trailing_comma + println!["Foo[,", ]; //~ unnecessary_trailing_comma + println!["Foo{{,}}", ]; //~ unnecessary_trailing_comma + println!{"Foo{{,}}", }; //~ unnecessary_trailing_comma + println!{"Foo(,", }; //~ unnecessary_trailing_comma + println!{"Foo[,", }; //~ unnecessary_trailing_comma + + // This should eventually work, but requires more work + println!(concat!("Foo", "=", "{}"), 1,); + println!("No params", /*"a,){ */); + println!("No params" /* "a,){*/, /*"a,){ */); + + // No trailing comma - no lint + println!("{}", 1); + println!(concat!("b", "o", "o")); + println!(concat!("Foo", "=", "{}"), 1); + + println!("Foo" ); + println!{"Foo" }; + println!["Foo" ]; + println!("Foo={}", 1); + println!(concat!("b", "o", "o")); + println!("Foo(,)"); + println!("Foo[,]"); + println!["Foo(,)"]; + println!["Foo[,]"]; + println!["Foo{{,}}"]; + println!{"Foo{{,}}"}; + println!{"Foo(,)"}; + println!{"Foo[,]"}; + println!["Foo(,"]; + println!["Foo[,"]; + println!["Foo{{,}}"]; + println!{"Foo{{,}}"}; + println!{"Foo(,"}; + println!{"Foo[,"}; + + // Multi-line macro - must NOT lint (single-line only) + println!( + "very long string to prevent fmt from making it into a single line: {}", + 1, + ); + + print!("{}" + , 1 + ,); +} + +// The macro invocation itself should never be fixed +// The call to println! on the other hand might be ok to suggest in the future + +macro_rules! from_macro { + (0,) => { + println!("Foo",); + }; + (1,) => { + println!("Foo={}", 1,); + }; +} + +fn from_macro() { + from_macro!(0,); + from_macro!(1,); +} diff --git a/src/tools/clippy/tests/ui/unnecessary_trailing_comma.stderr b/src/tools/clippy/tests/ui/unnecessary_trailing_comma.stderr new file mode 100644 index 0000000000000..06fd5b1861a55 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_trailing_comma.stderr @@ -0,0 +1,119 @@ +error: unnecessary trailing comma + --> tests/ui/unnecessary_trailing_comma.rs:10:19 + | +LL | println!("Foo" , ); + | ^^^ help: remove the trailing comma + | + = note: `-D clippy::unnecessary-trailing-comma` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_trailing_comma)]` + +error: unnecessary trailing comma + --> tests/ui/unnecessary_trailing_comma.rs:11:19 + | +LL | println!{"Foo" , }; + | ^^^ help: remove the trailing comma + +error: unnecessary trailing comma + --> tests/ui/unnecessary_trailing_comma.rs:12:19 + | +LL | println!["Foo" , ]; + | ^^^ help: remove the trailing comma + +error: unnecessary trailing comma + --> tests/ui/unnecessary_trailing_comma.rs:13:27 + | +LL | println!("Foo={}", 1 , ); + | ^^^^^ help: remove the trailing comma + +error: unnecessary trailing comma + --> tests/ui/unnecessary_trailing_comma.rs:14:36 + | +LL | println!(concat!("b", "o", "o") , ); + | ^^^^ help: remove the trailing comma + +error: unnecessary trailing comma + --> tests/ui/unnecessary_trailing_comma.rs:15:22 + | +LL | println!("Foo(,)",); + | ^ help: remove the trailing comma + +error: unnecessary trailing comma + --> tests/ui/unnecessary_trailing_comma.rs:16:22 + | +LL | println!("Foo[,]" , ); + | ^^^ help: remove the trailing comma + +error: unnecessary trailing comma + --> tests/ui/unnecessary_trailing_comma.rs:17:22 + | +LL | println!["Foo(,)", ]; + | ^^ help: remove the trailing comma + +error: unnecessary trailing comma + --> tests/ui/unnecessary_trailing_comma.rs:18:22 + | +LL | println!["Foo[,]", ]; + | ^^ help: remove the trailing comma + +error: unnecessary trailing comma + --> tests/ui/unnecessary_trailing_comma.rs:19:24 + | +LL | println!["Foo{{,}}", ]; + | ^^ help: remove the trailing comma + +error: unnecessary trailing comma + --> tests/ui/unnecessary_trailing_comma.rs:20:24 + | +LL | println!{"Foo{{,}}", }; + | ^^ help: remove the trailing comma + +error: unnecessary trailing comma + --> tests/ui/unnecessary_trailing_comma.rs:21:22 + | +LL | println!{"Foo(,)", }; + | ^^ help: remove the trailing comma + +error: unnecessary trailing comma + --> tests/ui/unnecessary_trailing_comma.rs:22:22 + | +LL | println!{"Foo[,]", }; + | ^^ help: remove the trailing comma + +error: unnecessary trailing comma + --> tests/ui/unnecessary_trailing_comma.rs:23:21 + | +LL | println!["Foo(,", ]; + | ^^ help: remove the trailing comma + +error: unnecessary trailing comma + --> tests/ui/unnecessary_trailing_comma.rs:24:21 + | +LL | println!["Foo[,", ]; + | ^^ help: remove the trailing comma + +error: unnecessary trailing comma + --> tests/ui/unnecessary_trailing_comma.rs:25:24 + | +LL | println!["Foo{{,}}", ]; + | ^^ help: remove the trailing comma + +error: unnecessary trailing comma + --> tests/ui/unnecessary_trailing_comma.rs:26:24 + | +LL | println!{"Foo{{,}}", }; + | ^^ help: remove the trailing comma + +error: unnecessary trailing comma + --> tests/ui/unnecessary_trailing_comma.rs:27:21 + | +LL | println!{"Foo(,", }; + | ^^ help: remove the trailing comma + +error: unnecessary trailing comma + --> tests/ui/unnecessary_trailing_comma.rs:28:21 + | +LL | println!{"Foo[,", }; + | ^^ help: remove the trailing comma + +error: aborting due to 19 previous errors + diff --git a/src/tools/clippy/tests/ui/unused_async.rs b/src/tools/clippy/tests/ui/unused_async.rs index 7a0be825a2de9..3f9244ab49707 100644 --- a/src/tools/clippy/tests/ui/unused_async.rs +++ b/src/tools/clippy/tests/ui/unused_async.rs @@ -115,10 +115,7 @@ macro_rules! async_trait_impl { } async_trait_impl!(); -fn main() { - foo(); - bar(); -} +fn main() {} mod issue14704 { use std::sync::Arc; diff --git a/src/tools/clippy/tests/ui/unused_peekable.rs b/src/tools/clippy/tests/ui/unused_peekable.rs index e7fe297764eb3..29e830fefb87d 100644 --- a/src/tools/clippy/tests/ui/unused_peekable.rs +++ b/src/tools/clippy/tests/ui/unused_peekable.rs @@ -3,10 +3,7 @@ use std::iter::{Empty, Peekable}; -fn main() { - invalid(); - valid(); -} +fn main() {} #[allow(clippy::unused_unit)] fn invalid() { diff --git a/src/tools/clippy/tests/ui/unused_peekable.stderr b/src/tools/clippy/tests/ui/unused_peekable.stderr index 9330d8c58001d..376c896a1c57c 100644 --- a/src/tools/clippy/tests/ui/unused_peekable.stderr +++ b/src/tools/clippy/tests/ui/unused_peekable.stderr @@ -1,5 +1,5 @@ error: `peek` never called on `Peekable` iterator - --> tests/ui/unused_peekable.rs:13:9 + --> tests/ui/unused_peekable.rs:10:9 | LL | let peekable = std::iter::empty::().peekable(); | ^^^^^^^^ @@ -9,7 +9,7 @@ LL | let peekable = std::iter::empty::().peekable(); = help: to override `-D warnings` add `#[allow(clippy::unused_peekable)]` error: `peek` never called on `Peekable` iterator - --> tests/ui/unused_peekable.rs:18:9 + --> tests/ui/unused_peekable.rs:15:9 | LL | let new_local = old_local; | ^^^^^^^^^ @@ -17,7 +17,7 @@ LL | let new_local = old_local; = help: consider removing the call to `peekable` error: `peek` never called on `Peekable` iterator - --> tests/ui/unused_peekable.rs:23:9 + --> tests/ui/unused_peekable.rs:20:9 | LL | let by_mut_ref = &mut by_mut_ref_test; | ^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | let by_mut_ref = &mut by_mut_ref_test; = help: consider removing the call to `peekable` error: `peek` never called on `Peekable` iterator - --> tests/ui/unused_peekable.rs:31:9 + --> tests/ui/unused_peekable.rs:28:9 | LL | let peekable_from_fn = returns_peekable(); | ^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | let peekable_from_fn = returns_peekable(); = help: consider removing the call to `peekable` error: `peek` never called on `Peekable` iterator - --> tests/ui/unused_peekable.rs:35:13 + --> tests/ui/unused_peekable.rs:32:13 | LL | let mut peekable_using_iterator_method = std::iter::empty::().peekable(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | let mut peekable_using_iterator_method = std::iter::empty::().peek = help: consider removing the call to `peekable` error: `peek` never called on `Peekable` iterator - --> tests/ui/unused_peekable.rs:42:9 + --> tests/ui/unused_peekable.rs:39:9 | LL | let passed_along_ref = std::iter::empty::().peekable(); | ^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | let passed_along_ref = std::iter::empty::().peekable(); = help: consider removing the call to `peekable` error: `peek` never called on `Peekable` iterator - --> tests/ui/unused_peekable.rs:49:9 + --> tests/ui/unused_peekable.rs:46:9 | LL | let _by_ref = by_ref_test.by_ref(); | ^^^^^^^ @@ -57,7 +57,7 @@ LL | let _by_ref = by_ref_test.by_ref(); = help: consider removing the call to `peekable` error: `peek` never called on `Peekable` iterator - --> tests/ui/unused_peekable.rs:52:13 + --> tests/ui/unused_peekable.rs:49:13 | LL | let mut peekable_in_for_loop = std::iter::empty::().peekable(); | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/useless_asref.fixed b/src/tools/clippy/tests/ui/useless_asref.fixed index 54a7c0a8c0802..5131ae113d184 100644 --- a/src/tools/clippy/tests/ui/useless_asref.fixed +++ b/src/tools/clippy/tests/ui/useless_asref.fixed @@ -293,7 +293,4 @@ fn issue16098(exts: Vec<&str>) { //~^ useless_asref } -fn main() { - not_ok(); - ok(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/useless_asref.rs b/src/tools/clippy/tests/ui/useless_asref.rs index 1b9ce1d462335..e1c2a1d81d04f 100644 --- a/src/tools/clippy/tests/ui/useless_asref.rs +++ b/src/tools/clippy/tests/ui/useless_asref.rs @@ -293,7 +293,4 @@ fn issue16098(exts: Vec<&str>) { //~^ useless_asref } -fn main() { - not_ok(); - ok(); -} +fn main() {} diff --git a/src/tools/clippy/tests/ui/useless_attribute.fixed b/src/tools/clippy/tests/ui/useless_attribute.fixed index dbe4b6fb50f3a..ff40f51c02054 100644 --- a/src/tools/clippy/tests/ui/useless_attribute.fixed +++ b/src/tools/clippy/tests/ui/useless_attribute.fixed @@ -96,9 +96,7 @@ mod module { #[allow(unused_braces)] use module::{Struct}; -fn main() { - test_indented_attr(); -} +fn main() {} // Regression test for https://github.com/rust-lang/rust-clippy/issues/4467 #[allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/useless_attribute.rs b/src/tools/clippy/tests/ui/useless_attribute.rs index 44fb6733f054d..426c720b4429e 100644 --- a/src/tools/clippy/tests/ui/useless_attribute.rs +++ b/src/tools/clippy/tests/ui/useless_attribute.rs @@ -96,9 +96,7 @@ mod module { #[allow(unused_braces)] use module::{Struct}; -fn main() { - test_indented_attr(); -} +fn main() {} // Regression test for https://github.com/rust-lang/rust-clippy/issues/4467 #[allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/useless_conversion.fixed b/src/tools/clippy/tests/ui/useless_conversion.fixed index 4832e922fa8e5..d0297ef6bcdc0 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.fixed +++ b/src/tools/clippy/tests/ui/useless_conversion.fixed @@ -117,21 +117,6 @@ fn dont_lint_into_iter_on_static_copy_iter() { } fn main() { - test_generic(10i32); - test_generic2::(10i32); - test_questionmark().unwrap(); - test_issue_3913().unwrap(); - - dont_lint_on_type_alias(); - dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr(); - lint_into_iter_on_mutable_local_implementing_iterator_in_expr(); - lint_into_iter_on_expr_implementing_iterator(); - lint_into_iter_on_expr_implementing_iterator_2(); - lint_into_iter_on_const_implementing_iterator(); - lint_into_iter_on_const_implementing_iterator_2(); - dont_lint_into_iter_on_copy_iter(); - dont_lint_into_iter_on_static_copy_iter(); - { // triggers the IntoIterator trait fn consume(_: impl IntoIterator) {} @@ -463,3 +448,34 @@ fn issue16165() { for _ in mac!(iter [1, 2]) {} //~^ useless_conversion } + +fn takes_into_iter_usize(_: impl IntoIterator) {} +fn takes_into_iter_usize_result(_: impl IntoIterator) -> Result<(), ()> { + Ok(()) +} + +async fn issue16590() { + let a: Vec = vec![]; + let b: Vec = vec![]; + + takes_into_iter_usize(b); + //~^ useless_conversion +} + +fn in_for_loop() { + let a: Vec = vec![1, 2, 3]; + let b: Vec = vec![4, 5, 6]; + + for _ in &a { + takes_into_iter_usize(b.clone()); + //~^ useless_conversion + } +} + +fn after_question_mark() -> Result<(), ()> { + let b: Vec = vec![4, 5, 6]; + + takes_into_iter_usize_result(b.clone())?; + //~^ useless_conversion + Ok(()) +} diff --git a/src/tools/clippy/tests/ui/useless_conversion.rs b/src/tools/clippy/tests/ui/useless_conversion.rs index 6ef1f93a5606b..20a0f6d72f9a8 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.rs +++ b/src/tools/clippy/tests/ui/useless_conversion.rs @@ -117,21 +117,6 @@ fn dont_lint_into_iter_on_static_copy_iter() { } fn main() { - test_generic(10i32); - test_generic2::(10i32); - test_questionmark().unwrap(); - test_issue_3913().unwrap(); - - dont_lint_on_type_alias(); - dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr(); - lint_into_iter_on_mutable_local_implementing_iterator_in_expr(); - lint_into_iter_on_expr_implementing_iterator(); - lint_into_iter_on_expr_implementing_iterator_2(); - lint_into_iter_on_const_implementing_iterator(); - lint_into_iter_on_const_implementing_iterator_2(); - dont_lint_into_iter_on_copy_iter(); - dont_lint_into_iter_on_static_copy_iter(); - { // triggers the IntoIterator trait fn consume(_: impl IntoIterator) {} @@ -463,3 +448,34 @@ fn issue16165() { for _ in mac!(iter [1, 2]).into_iter() {} //~^ useless_conversion } + +fn takes_into_iter_usize(_: impl IntoIterator) {} +fn takes_into_iter_usize_result(_: impl IntoIterator) -> Result<(), ()> { + Ok(()) +} + +async fn issue16590() { + let a: Vec = vec![]; + let b: Vec = vec![]; + + takes_into_iter_usize(b.into_iter()); + //~^ useless_conversion +} + +fn in_for_loop() { + let a: Vec = vec![1, 2, 3]; + let b: Vec = vec![4, 5, 6]; + + for _ in &a { + takes_into_iter_usize(b.clone().into_iter()); + //~^ useless_conversion + } +} + +fn after_question_mark() -> Result<(), ()> { + let b: Vec = vec![4, 5, 6]; + + takes_into_iter_usize_result(b.clone().into_iter())?; + //~^ useless_conversion + Ok(()) +} diff --git a/src/tools/clippy/tests/ui/useless_conversion.stderr b/src/tools/clippy/tests/ui/useless_conversion.stderr index 24772af3818ea..18d5c9d28c0dc 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.stderr +++ b/src/tools/clippy/tests/ui/useless_conversion.stderr @@ -53,13 +53,13 @@ LL | let mut n = NUMBERS.into_iter(); | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:141:17 + --> tests/ui/useless_conversion.rs:126:17 | LL | consume(items.into_iter()); | ^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:137:28 + --> tests/ui/useless_conversion.rs:122:28 | LL | fn consume(_: impl IntoIterator) {} | ^^^^^^^^^^^^ @@ -70,79 +70,79 @@ LL + consume(*items); | error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:154:21 + --> tests/ui/useless_conversion.rs:139:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:156:21 + --> tests/ui/useless_conversion.rs:141:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:158:13 + --> tests/ui/useless_conversion.rs:143:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:160:13 + --> tests/ui/useless_conversion.rs:145:13 | LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:162:13 + --> tests/ui/useless_conversion.rs:147:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` error: useless conversion to the same type: `std::vec::IntoIter` - --> tests/ui/useless_conversion.rs:164:13 + --> tests/ui/useless_conversion.rs:149:13 | LL | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:166:21 + --> tests/ui/useless_conversion.rs:151:21 | LL | let _: String = format!("Hello {}", "world").into(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")` error: useless conversion to the same type: `i32` - --> tests/ui/useless_conversion.rs:172:13 + --> tests/ui/useless_conversion.rs:157:13 | LL | let _ = i32::from(a + b) * 3; | ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)` error: useless conversion to the same type: `Foo<'a'>` - --> tests/ui/useless_conversion.rs:179:23 + --> tests/ui/useless_conversion.rs:164:23 | LL | let _: Foo<'a'> = s2.into(); | ^^^^^^^^^ help: consider removing `.into()`: `s2` error: useless conversion to the same type: `Foo<'a'>` - --> tests/ui/useless_conversion.rs:182:13 + --> tests/ui/useless_conversion.rs:167:13 | LL | let _ = Foo::<'a'>::from(s3); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing `Foo::<'a'>::from()`: `s3` error: useless conversion to the same type: `std::vec::IntoIter>` - --> tests/ui/useless_conversion.rs:185:13 + --> tests/ui/useless_conversion.rs:170:13 | LL | let _ = vec![s4, s4, s4].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()` error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:218:7 + --> tests/ui/useless_conversion.rs:203:7 | LL | b(vec![1, 2].into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:208:13 + --> tests/ui/useless_conversion.rs:193:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -153,13 +153,13 @@ LL + b(vec![1, 2]); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:220:7 + --> tests/ui/useless_conversion.rs:205:7 | LL | c(vec![1, 2].into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:209:18 + --> tests/ui/useless_conversion.rs:194:18 | LL | fn c(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -170,13 +170,13 @@ LL + c(vec![1, 2]); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:222:7 + --> tests/ui/useless_conversion.rs:207:7 | LL | d(vec![1, 2].into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:212:12 + --> tests/ui/useless_conversion.rs:197:12 | LL | T: IntoIterator, | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -187,13 +187,13 @@ LL + d(vec![1, 2]); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:226:7 + --> tests/ui/useless_conversion.rs:211:7 | LL | b(vec![1, 2].into_iter().into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:208:13 + --> tests/ui/useless_conversion.rs:193:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -204,13 +204,13 @@ LL + b(vec![1, 2]); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:228:7 + --> tests/ui/useless_conversion.rs:213:7 | LL | b(vec![1, 2].into_iter().into_iter().into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:208:13 + --> tests/ui/useless_conversion.rs:193:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -221,13 +221,13 @@ LL + b(vec![1, 2]); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:275:24 + --> tests/ui/useless_conversion.rs:260:24 | LL | foo2::([1, 2, 3].into_iter()); | ^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:254:12 + --> tests/ui/useless_conversion.rs:239:12 | LL | I: IntoIterator + Helper, | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -238,13 +238,13 @@ LL + foo2::([1, 2, 3]); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:284:14 + --> tests/ui/useless_conversion.rs:269:14 | LL | foo3([1, 2, 3].into_iter()); | ^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:263:12 + --> tests/ui/useless_conversion.rs:248:12 | LL | I: IntoIterator, | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -255,13 +255,13 @@ LL + foo3([1, 2, 3]); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:294:16 + --> tests/ui/useless_conversion.rs:279:16 | LL | S1.foo([1, 2].into_iter()); | ^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:291:27 + --> tests/ui/useless_conversion.rs:276:27 | LL | pub fn foo(&self, _: I) {} | ^^^^^^^^^^^^ @@ -272,13 +272,13 @@ LL + S1.foo([1, 2]); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:314:44 + --> tests/ui/useless_conversion.rs:299:44 | LL | v0.into_iter().interleave_shortest(v1.into_iter()); | ^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:301:20 + --> tests/ui/useless_conversion.rs:286:20 | LL | J: IntoIterator, | ^^^^^^^^^^^^ @@ -289,61 +289,61 @@ LL + v0.into_iter().interleave_shortest(v1); | error: useless conversion to the same type: `()` - --> tests/ui/useless_conversion.rs:342:58 + --> tests/ui/useless_conversion.rs:327:58 | LL | let _: Result<(), std::io::Error> = test_issue_3913().map(Into::into); | ^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `std::io::Error` - --> tests/ui/useless_conversion.rs:345:58 + --> tests/ui/useless_conversion.rs:330:58 | LL | let _: Result<(), std::io::Error> = test_issue_3913().map_err(Into::into); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `()` - --> tests/ui/useless_conversion.rs:348:58 + --> tests/ui/useless_conversion.rs:333:58 | LL | let _: Result<(), std::io::Error> = test_issue_3913().map(From::from); | ^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `std::io::Error` - --> tests/ui/useless_conversion.rs:351:58 + --> tests/ui/useless_conversion.rs:336:58 | LL | let _: Result<(), std::io::Error> = test_issue_3913().map_err(From::from); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `()` - --> tests/ui/useless_conversion.rs:355:31 + --> tests/ui/useless_conversion.rs:340:31 | LL | let _: ControlFlow<()> = c.map_break(Into::into); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `()` - --> tests/ui/useless_conversion.rs:359:31 + --> tests/ui/useless_conversion.rs:344:31 | LL | let _: ControlFlow<()> = c.map_continue(Into::into); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `u32` - --> tests/ui/useless_conversion.rs:373:41 + --> tests/ui/useless_conversion.rs:358:41 | LL | let _: Vec = [1u32].into_iter().map(Into::into).collect(); | ^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `T` - --> tests/ui/useless_conversion.rs:384:18 + --> tests/ui/useless_conversion.rs:369:18 | LL | x.into_iter().map(Into::into).collect() | ^^^^^^^^^^^^^^^^ help: consider removing error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:400:29 + --> tests/ui/useless_conversion.rs:385:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:389:32 + --> tests/ui/useless_conversion.rs:374:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -354,13 +354,13 @@ LL + takes_into_iter(&self.my_field); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:408:29 + --> tests/ui/useless_conversion.rs:393:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:389:32 + --> tests/ui/useless_conversion.rs:374:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -371,13 +371,13 @@ LL + takes_into_iter(&mut self.my_field); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:417:29 + --> tests/ui/useless_conversion.rs:402:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:389:32 + --> tests/ui/useless_conversion.rs:374:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -388,13 +388,13 @@ LL + takes_into_iter(*self.my_field); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:426:29 + --> tests/ui/useless_conversion.rs:411:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:389:32 + --> tests/ui/useless_conversion.rs:374:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -405,13 +405,13 @@ LL + takes_into_iter(&*self.my_field); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:435:29 + --> tests/ui/useless_conversion.rs:420:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:389:32 + --> tests/ui/useless_conversion.rs:374:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -422,22 +422,73 @@ LL + takes_into_iter(&mut *self.my_field); | error: useless conversion to the same type: `std::ops::Range` - --> tests/ui/useless_conversion.rs:450:5 + --> tests/ui/useless_conversion.rs:435:5 | LL | R.into_iter().for_each(|_x| {}); | ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R` error: useless conversion to the same type: `std::ops::Range` - --> tests/ui/useless_conversion.rs:452:13 + --> tests/ui/useless_conversion.rs:437:13 | LL | let _ = R.into_iter().map(|_x| 0); | ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R` error: useless conversion to the same type: `std::slice::Iter<'_, i32>` - --> tests/ui/useless_conversion.rs:463:14 + --> tests/ui/useless_conversion.rs:448:14 | LL | for _ in mac!(iter [1, 2]).into_iter() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `mac!(iter [1, 2])` -error: aborting due to 45 previous errors +error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` + --> tests/ui/useless_conversion.rs:461:27 + | +LL | takes_into_iter_usize(b.into_iter()); + | ^^^^^^^^^^^^^ + | +note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` + --> tests/ui/useless_conversion.rs:452:34 + | +LL | fn takes_into_iter_usize(_: impl IntoIterator) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider removing the `.into_iter()` + | +LL - takes_into_iter_usize(b.into_iter()); +LL + takes_into_iter_usize(b); + | + +error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` + --> tests/ui/useless_conversion.rs:470:31 + | +LL | takes_into_iter_usize(b.clone().into_iter()); + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` + --> tests/ui/useless_conversion.rs:452:34 + | +LL | fn takes_into_iter_usize(_: impl IntoIterator) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider removing the `.into_iter()` + | +LL - takes_into_iter_usize(b.clone().into_iter()); +LL + takes_into_iter_usize(b.clone()); + | + +error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` + --> tests/ui/useless_conversion.rs:478:34 + | +LL | takes_into_iter_usize_result(b.clone().into_iter())?; + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` + --> tests/ui/useless_conversion.rs:453:41 + | +LL | fn takes_into_iter_usize_result(_: impl IntoIterator) -> Result<(), ()> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider removing the `.into_iter()` + | +LL - takes_into_iter_usize_result(b.clone().into_iter())?; +LL + takes_into_iter_usize_result(b.clone())?; + | + +error: aborting due to 48 previous errors diff --git a/src/tools/clippy/tests/ui/while_immutable_condition.rs b/src/tools/clippy/tests/ui/while_immutable_condition.rs index 5c18cd41ff792..569a0c006aba2 100644 --- a/src/tools/clippy/tests/ui/while_immutable_condition.rs +++ b/src/tools/clippy/tests/ui/while_immutable_condition.rs @@ -226,16 +226,4 @@ fn immutable_condition_false_positive(mut n: u64) -> u32 { count } -fn main() { - immutable_condition(); - unused_var(); - used_immutable(); - internally_mutable(); - immutable_condition_false_positive(5); - - let mut c = Counter { count: 0 }; - c.inc_n(5); - c.print_n(2); - - while_loop_with_break_and_return(); -} +fn main() {}