From 9798fafcb72490edde615fba603e595d8436d190 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 14 Oct 2025 10:48:53 -0400 Subject: [PATCH 01/14] `clippy_dev`: Rename `update_lints` module to `generate` --- clippy_dev/src/edit_lints.rs | 2 +- clippy_dev/src/{update_lints.rs => generate.rs} | 0 clippy_dev/src/lib.rs | 2 +- clippy_dev/src/main.rs | 10 ++++++---- 4 files changed, 8 insertions(+), 6 deletions(-) rename clippy_dev/src/{update_lints.rs => generate.rs} (100%) diff --git a/clippy_dev/src/edit_lints.rs b/clippy_dev/src/edit_lints.rs index 411bf530b22b..3dd667165d58 100644 --- a/clippy_dev/src/edit_lints.rs +++ b/clippy_dev/src/edit_lints.rs @@ -1,6 +1,6 @@ +use crate::generate::generate_lint_files; use crate::parse::cursor::{self, Capture, Cursor}; 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, diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/generate.rs similarity index 100% rename from clippy_dev/src/update_lints.rs rename to clippy_dev/src/generate.rs diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index cff51d34c30e..c3f4ed08bf67 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -27,13 +27,13 @@ extern crate rustc_lexer; pub mod dogfood; pub mod edit_lints; pub mod fmt; +pub mod generate; pub mod lint; pub mod new_lint; pub mod release; pub mod serve; pub mod setup; pub mod sync; -pub mod update_lints; mod parse; mod utils; diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 8dc2290df8e4..ba470d90014a 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -4,8 +4,8 @@ use clap::{Args, Parser, Subcommand}; use clippy_dev::{ - ClippyInfo, UpdateMode, dogfood, edit_lints, fmt, lint, new_lint, new_parse_cx, release, serve, setup, sync, - update_lints, + ClippyInfo, UpdateMode, dogfood, edit_lints, fmt, generate, lint, new_lint, new_parse_cx, release, serve, setup, + sync, }; use std::env; @@ -27,7 +27,9 @@ fn main() { allow_no_vcs, } => dogfood::dogfood(fix, allow_dirty, allow_staged, allow_no_vcs), DevCommand::Fmt { check } => fmt::run(UpdateMode::from_check(check)), - DevCommand::UpdateLints { check } => new_parse_cx(|cx| update_lints::update(cx, UpdateMode::from_check(check))), + DevCommand::UpdateLints { check } => { + new_parse_cx(|cx| generate::generate_lint_files(UpdateMode::from_check(check), &cx.parse_lint_decls())); + }, DevCommand::NewLint { pass, name, @@ -35,7 +37,7 @@ fn main() { r#type, msrv, } => match new_lint::create(clippy.version, pass, &name, &category, r#type.as_deref(), msrv) { - Ok(()) => new_parse_cx(|cx| update_lints::update(cx, UpdateMode::Change)), + Ok(()) => new_parse_cx(|cx| generate::generate_lint_files(UpdateMode::Change, &cx.parse_lint_decls())), Err(e) => eprintln!("Unable to create lint: {e}"), }, DevCommand::Setup(SetupCommand { subcommand }) => match subcommand { From 1f2be4e71b06e2f37ef52dd08821023d3f34ca15 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Fri, 24 Oct 2025 21:24:35 -0400 Subject: [PATCH 02/14] `clippy_dev`: Parse and format lint pass macros. --- clippy_dev/src/edit_lints.rs | 11 +- clippy_dev/src/fmt.rs | 27 +- clippy_dev/src/generate.rs | 392 ++++++++++-------- clippy_dev/src/lib.rs | 2 +- clippy_dev/src/main.rs | 7 +- clippy_dev/src/parse.rs | 161 ++++++- clippy_dev/src/parse/cursor.rs | 86 +++- clippy_dev/src/utils.rs | 24 ++ clippy_lints/src/attrs/mod.rs | 15 +- clippy_lints/src/await_holding_invalid.rs | 6 +- clippy_lints/src/cargo/mod.rs | 6 +- clippy_lints/src/casts/mod.rs | 38 +- clippy_lints/src/collapsible_if.rs | 2 +- .../src/default_constructed_unit_structs.rs | 4 +- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/derive/mod.rs | 4 +- clippy_lints/src/doc/mod.rs | 22 +- clippy_lints/src/drop_forget_ref.rs | 6 +- clippy_lints/src/empty_line_after.rs | 2 +- clippy_lints/src/empty_with_brackets.rs | 5 +- clippy_lints/src/endian_bytes.rs | 6 +- clippy_lints/src/eta_reduction.rs | 5 +- clippy_lints/src/excessive_bools.rs | 5 +- .../src/field_scoped_visibility_modifiers.rs | 4 +- clippy_lints/src/float_literal.rs | 4 +- .../src/floating_point_arithmetic/mod.rs | 5 +- clippy_lints/src/format_args.rs | 4 +- clippy_lints/src/format_impl.rs | 2 +- clippy_lints/src/formatting.rs | 6 +- clippy_lints/src/functions/mod.rs | 18 +- clippy_lints/src/ifs/mod.rs | 4 +- .../impl_hash_with_borrow_str_and_bytes.rs | 4 +- clippy_lints/src/implicit_saturating_sub.rs | 5 +- .../src/inconsistent_struct_constructor.rs | 4 +- clippy_lints/src/inherent_to_string.rs | 5 +- clippy_lints/src/item_name_repetitions.rs | 4 +- clippy_lints/src/iter_without_into_iter.rs | 5 +- clippy_lints/src/len_zero.rs | 2 +- clippy_lints/src/let_underscore.rs | 7 +- clippy_lints/src/lifetimes.rs | 2 +- clippy_lints/src/literal_representation.rs | 2 +- .../literal_string_with_formatting_args.rs | 4 +- clippy_lints/src/loops/mod.rs | 36 +- clippy_lints/src/manual_float_methods.rs | 2 +- clippy_lints/src/matches/mod.rs | 42 +- clippy_lints/src/mem_replace.rs | 8 +- clippy_lints/src/methods/mod.rs | 244 +++++------ clippy_lints/src/misc.rs | 2 +- clippy_lints/src/misc_early/mod.rs | 12 +- .../src/mixed_read_write_in_expression.rs | 5 +- clippy_lints/src/mut_key.rs | 2 +- .../src/needless_borrows_for_generic_args.rs | 4 +- .../src/needless_parens_on_range_literals.rs | 4 +- clippy_lints/src/no_effect.rs | 6 +- clippy_lints/src/non_canonical_impls.rs | 5 +- clippy_lints/src/non_copy_const.rs | 5 +- clippy_lints/src/non_expressive_names.rs | 6 +- clippy_lints/src/only_used_in_recursion.rs | 5 +- clippy_lints/src/operators/mod.rs | 32 +- clippy_lints/src/panic_in_result_fn.rs | 2 +- clippy_lints/src/panic_unimplemented.rs | 2 +- clippy_lints/src/pass_by_ref_or_value.rs | 5 +- .../src/permissions_set_readonly_false.rs | 4 +- clippy_lints/src/ptr/mod.rs | 2 +- clippy_lints/src/question_mark.rs | 2 +- clippy_lints/src/ranges.rs | 4 +- clippy_lints/src/redundant_slicing.rs | 2 +- clippy_lints/src/regex.rs | 2 +- clippy_lints/src/returns/mod.rs | 6 +- clippy_lints/src/shadow.rs | 2 +- clippy_lints/src/std_instead_of_core.rs | 6 +- clippy_lints/src/string_patterns.rs | 5 +- clippy_lints/src/strings.rs | 5 +- .../src/suspicious_operation_groupings.rs | 4 +- clippy_lints/src/suspicious_trait_impl.rs | 5 +- clippy_lints/src/swap.rs | 2 +- clippy_lints/src/time_subtraction.rs | 5 +- clippy_lints/src/trait_bounds.rs | 5 +- clippy_lints/src/transmute/mod.rs | 18 +- clippy_lints/src/types/mod.rs | 10 +- .../src/undocumented_unsafe_blocks.rs | 5 +- clippy_lints/src/unicode.rs | 6 +- clippy_lints/src/unit_types/mod.rs | 2 +- .../src/unnecessary_map_on_constructor.rs | 4 +- .../src/unnecessary_owned_empty_strings.rs | 4 +- clippy_lints/src/unwrap_in_result.rs | 2 +- clippy_lints/src/visibility.rs | 6 +- clippy_lints/src/write/mod.rs | 8 +- 88 files changed, 941 insertions(+), 543 deletions(-) diff --git a/clippy_dev/src/edit_lints.rs b/clippy_dev/src/edit_lints.rs index 3dd667165d58..70c096783af8 100644 --- a/clippy_dev/src/edit_lints.rs +++ b/clippy_dev/src/edit_lints.rs @@ -1,4 +1,3 @@ -use crate::generate::generate_lint_files; use crate::parse::cursor::{self, Capture, Cursor}; use crate::parse::{ActiveLint, DeprecatedLint, Lint, LintData, LintName, ParseCx, RenamedLint}; use crate::utils::{ @@ -40,7 +39,7 @@ pub fn deprecate<'cx, 'env: 'cx>(cx: ParseCx<'cx>, clippy_version: Version, name }; remove_lint_declaration(name, &prev_lint, &data, &mut FileUpdater::default()); - generate_lint_files(UpdateMode::Change, &data); + data.gen_decls(UpdateMode::Change); println!("info: `{name}` has successfully been deprecated"); println!("note: you must run `cargo uitest` to update the test results"); } @@ -74,7 +73,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, &data); + data.gen_decls(UpdateMode::Change); println!("info: `{old_name}` has successfully been uplifted as `{new_name}`"); println!("note: you must run `cargo uitest` to update the test results"); } @@ -151,7 +150,7 @@ 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, &data); + data.gen_decls(UpdateMode::Change); println!("Renamed `{old_name}` to `{new_name}`"); println!("All code referencing the old name has been updated"); @@ -172,11 +171,11 @@ fn remove_lint_declaration(name: &str, lint: &ActiveLint<'_>, data: &LintData<'_ delete_file_if_exists(lint.path.as_ref()) } else { updater.update_file(&lint.path, &mut |_, src, dst| -> UpdateStatus { - let mut start = &src[..lint.declaration_range.start]; + let mut start = &src[..lint.declaration_range.start as usize]; if start.ends_with("\n\n") { start = &start[..start.len() - 1]; } - let mut end = &src[lint.declaration_range.end..]; + let mut end = &src[lint.declaration_range.end as usize..]; if end.starts_with("\n\n") { end = &end[1..]; } diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index 781e37e6144e..f4ee600dde04 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -1,6 +1,7 @@ +use crate::new_parse_cx; use crate::utils::{ - ErrAction, FileUpdater, UpdateMode, UpdateStatus, expect_action, run_with_output, split_args_for_threads, - walk_dir_no_dot_or_target, + ErrAction, FileUpdater, UpdateMode, UpdateStatus, expect_action, run_with_output, slice_groups, + split_args_for_threads, walk_dir_no_dot_or_target, }; use itertools::Itertools; use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize}; @@ -326,10 +327,30 @@ fn run_rustfmt(update_mode: UpdateMode) { // the "main" function of cargo dev fmt pub fn run(update_mode: UpdateMode) { - run_rustfmt(update_mode); fmt_syms(update_mode); if let Err(e) = fmt_conf(update_mode.is_check()) { e.display(); process::exit(1); } + + new_parse_cx(|cx| { + let data = cx.parse_lint_decls(); + let mut updater = FileUpdater::default(); + + for passes in slice_groups(&data.lint_passes, |head, tail| { + tail.iter().take_while(|&x| x.path == head.path).count() + }) { + updater.update_file_checked("cargo dev fmt", update_mode, &passes[0].path, &mut |_, src, dst| { + let pos = passes.iter().fold(0u32, |start, pass| { + dst.push_str(&src[start as usize..pass.decl_range.start as usize]); + pass.gen_mac(dst); + pass.decl_range.end + }); + dst.push_str(&src[pos as usize..]); + UpdateStatus::from_changed(src != dst) + }); + } + }); + + run_rustfmt(update_mode); } diff --git a/clippy_dev/src/generate.rs b/clippy_dev/src/generate.rs index a4cf15058986..0d86c0179cde 100644 --- a/clippy_dev/src/generate.rs +++ b/clippy_dev/src/generate.rs @@ -1,5 +1,5 @@ use crate::parse::cursor::Cursor; -use crate::parse::{Lint, LintData, ParseCx}; +use crate::parse::{Lint, LintData, LintPass}; use crate::utils::{FileUpdater, UpdateMode, UpdateStatus, update_text_region_fn}; use itertools::Itertools; use std::collections::HashSet; @@ -12,193 +12,247 @@ const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev u const DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html"; -/// Runs the `update_lints` command. -/// -/// This updates various generated values from the lint source code. -/// -/// `update_mode` indicates if the files should be updated or if updates should be checked for. -/// -/// # Panics -/// -/// Panics if a file path could not read from or then written to -pub fn update(cx: ParseCx<'_>, update_mode: UpdateMode) { - 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, 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, - "CHANGELOG.md", - &mut update_text_region_fn( - "\n", - "", - |dst| { - for &(lint, _) in &lints { - writeln!(dst, "[`{lint}`]: {DOCS_LINK}#{lint}").unwrap(); - } - }, - ), - ); +impl LintData<'_> { + #[expect(clippy::too_many_lines)] + pub fn gen_decls(&self, update_mode: UpdateMode) { + let mut updater = FileUpdater::default(); - 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, - "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, - "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, - "clippy_lints/src/deprecated_lints.rs", - &mut |_, src, dst| { - let mut cursor = Cursor::new(src); - assert!( - cursor.find_ident("declare_with_version").is_some() - && cursor.find_ident("declare_with_version").is_some(), - "error reading deprecated lints" - ); - dst.push_str(&src[..cursor.pos() as usize]); - dst.push_str("! { DEPRECATED(DEPRECATED_VERSION) = [\n"); - for &(name, data) in &deprecated { - write!( - dst, - " #[clippy::version = \"{}\"]\n (\"clippy::{name}\", \"{}\"),\n", - data.version, data.reason, - ) - .unwrap(); - } - dst.push_str( - "]}\n\n\ - #[rustfmt::skip]\n\ - declare_with_version! { RENAMED(RENAMED_VERSION) = [\n\ - ", - ); - for &(name, data) in &renamed { - write!( - dst, - " #[clippy::version = \"{}\"]\n (\"clippy::{name}\", \"{}\"),\n", - data.version, data.new_name, - ) - .unwrap(); - } - dst.push_str("]}\n"); - UpdateStatus::from_changed(src != dst) - }, - ); - updater.update_file_checked( - "cargo dev update_lints", - update_mode, - "tests/ui/deprecated.rs", - &mut |_, src, dst| { - dst.push_str(GENERATED_FILE_COMMENT); - 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) - }, - ); - updater.update_file_checked( - "cargo dev update_lints", - update_mode, - "tests/ui/rename.rs", - &mut move |_, src, dst| { - let mut seen_lints = HashSet::new(); - dst.push_str(GENERATED_FILE_COMMENT); - dst.push_str("#![allow(clippy::duplicated_attributes)]\n"); - for &(_, lint) in &renamed { - if seen_lints.insert(lint.new_name) { - writeln!(dst, "#![allow({})]", lint.new_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 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 `{}`", - lint.path.display() - ); - }; - name - }) { + let mut lints: Vec<_> = self.lints.iter().map(|(&x, y)| (x, y)).collect(); + lints.sort_by_key(|&(x, _)| x); updater.update_file_checked( "cargo dev update_lints", update_mode, - Path::new(crate_name).join("src/lib.rs"), + "CHANGELOG.md", &mut update_text_region_fn( - "// 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`", + "\n", + "", |dst| { - let mut prev = ""; - for &(_, lint) in &lints { - if lint.module != prev { - writeln!(dst, "mod {};", lint.module).unwrap(); - prev = lint.module; - } + 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, + "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, - Path::new(crate_name).join("src/declared_lints.rs"), + "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, + "clippy_lints/src/deprecated_lints.rs", + &mut |_, src, dst| { + let mut cursor = Cursor::new(src); + assert!( + cursor.find_ident("declare_with_version").is_some() + && cursor.find_ident("declare_with_version").is_some(), + "error reading deprecated lints" + ); + dst.push_str(&src[..cursor.pos() as usize]); + dst.push_str("! { DEPRECATED(DEPRECATED_VERSION) = [\n"); + for &(name, data) in &deprecated { + write!( + dst, + " #[clippy::version = \"{}\"]\n (\"clippy::{name}\", \"{}\"),\n", + data.version, data.reason, + ) + .unwrap(); + } + dst.push_str( + "]}\n\n\ + #[rustfmt::skip]\n\ + declare_with_version! { RENAMED(RENAMED_VERSION) = [\n\ + ", + ); + for &(name, data) in &renamed { + write!( + dst, + " #[clippy::version = \"{}\"]\n (\"clippy::{name}\", \"{}\"),\n", + data.version, data.new_name, + ) + .unwrap(); + } + dst.push_str("]}\n"); + UpdateStatus::from_changed(src != dst) + }, + ); + updater.update_file_checked( + "cargo dev update_lints", + update_mode, + "tests/ui/deprecated.rs", &mut |_, src, dst| { dst.push_str(GENERATED_FILE_COMMENT); - dst.push_str("pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[\n"); - 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::{}::{buf}_INFO,", lint.module).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) + }, + ); + updater.update_file_checked( + "cargo dev update_lints", + update_mode, + "tests/ui/rename.rs", + &mut move |_, src, dst| { + let mut seen_lints = HashSet::new(); + dst.push_str(GENERATED_FILE_COMMENT); + dst.push_str("#![allow(clippy::duplicated_attributes)]\n"); + for &(_, lint) in &renamed { + if seen_lints.insert(lint.new_name) { + writeln!(dst, "#![allow({})]", lint.new_name).unwrap(); } } - dst.push_str("];\n"); + 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 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 `{}`", + lint.path.display() + ); + }; + name + }) { + updater.update_file_checked( + "cargo dev update_lints", + update_mode, + Path::new(crate_name).join("src/lib.rs"), + &mut update_text_region_fn( + "// 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| { + let mut prev = ""; + for &(_, lint) in &lints { + if lint.module != prev { + writeln!(dst, "mod {};", lint.module).unwrap(); + prev = lint.module; + } + } + }, + ), + ); + updater.update_file_checked( + "cargo dev update_lints", + update_mode, + Path::new(crate_name).join("src/declared_lints.rs"), + &mut |_, src, dst| { + dst.push_str(GENERATED_FILE_COMMENT); + dst.push_str("pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[\n"); + 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::{}::{buf}_INFO,", lint.module).unwrap(); + } + } + dst.push_str("];\n"); + UpdateStatus::from_changed(src != dst) + }, + ); + } + } +} + +impl LintPass<'_> { + pub fn gen_mac(&self, dst: &mut String) { + let mut line_start = dst.len(); + dst.extend([self.mac.name(), "!("]); + let has_docs = write_comment_lines(self.docs, "\n ", dst); + let (list_indent, list_multi_end, end) = if has_docs { + dst.push_str("\n "); + line_start = dst.len() - 4; + (" ", "\n ", "]\n);") + } else { + (" ", "\n", "]);") + }; + dst.push_str(self.name); + if let Some(lt) = self.lt { + dst.extend(["<", lt, ">"]); + } + dst.push_str(" => ["); + let fmt = write_list( + self.lints.iter().copied(), + 80usize.saturating_sub(dst.len() - line_start), + list_indent, + dst, + ); + if matches!(fmt, ListFmt::MultiLine) { + dst.push_str(list_multi_end); + } + dst.push_str(end); + } +} + +fn write_comment_lines(s: &str, prefix: &str, dst: &mut String) -> bool { + let mut has_doc = false; + for line in s.split('\n') { + let line = line.trim_start(); + if !line.is_empty() { + has_doc = true; + dst.extend([prefix, line]); + } + } + has_doc +} + +#[derive(Clone, Copy)] +enum ListFmt { + SingleLine, + MultiLine, +} + +fn write_list<'a>( + items: impl Iterator + Clone, + single_line_limit: usize, + indent: &str, + dst: &mut String, +) -> ListFmt { + let len = items.clone().map(str::len).sum::(); + if len > single_line_limit { + for item in items { + dst.extend(["\n", indent, item, ","]); + } + ListFmt::MultiLine + } else { + let _ = write!(dst, "{}", items.format(", ")); + ListFmt::SingleLine } } diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index c3f4ed08bf67..27288cbdefd0 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -27,7 +27,6 @@ extern crate rustc_lexer; pub mod dogfood; pub mod edit_lints; pub mod fmt; -pub mod generate; pub mod lint; pub mod new_lint; pub mod release; @@ -35,6 +34,7 @@ pub mod serve; pub mod setup; pub mod sync; +mod generate; mod parse; mod utils; diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index ba470d90014a..5fe2295a1e21 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -4,8 +4,7 @@ use clap::{Args, Parser, Subcommand}; use clippy_dev::{ - ClippyInfo, UpdateMode, dogfood, edit_lints, fmt, generate, lint, new_lint, new_parse_cx, release, serve, setup, - sync, + ClippyInfo, UpdateMode, dogfood, edit_lints, fmt, lint, new_lint, new_parse_cx, release, serve, setup, sync, }; use std::env; @@ -28,7 +27,7 @@ fn main() { } => dogfood::dogfood(fix, allow_dirty, allow_staged, allow_no_vcs), DevCommand::Fmt { check } => fmt::run(UpdateMode::from_check(check)), DevCommand::UpdateLints { check } => { - new_parse_cx(|cx| generate::generate_lint_files(UpdateMode::from_check(check), &cx.parse_lint_decls())); + new_parse_cx(|cx| cx.parse_lint_decls().gen_decls(UpdateMode::from_check(check))); }, DevCommand::NewLint { pass, @@ -37,7 +36,7 @@ fn main() { r#type, msrv, } => match new_lint::create(clippy.version, pass, &name, &category, r#type.as_deref(), msrv) { - Ok(()) => new_parse_cx(|cx| generate::generate_lint_files(UpdateMode::Change, &cx.parse_lint_decls())), + Ok(()) => new_parse_cx(|cx| cx.parse_lint_decls().gen_decls(UpdateMode::Change)), Err(e) => eprintln!("Unable to create lint: {e}"), }, DevCommand::Setup(SetupCommand { subcommand }) => match subcommand { diff --git a/clippy_dev/src/parse.rs b/clippy_dev/src/parse.rs index ffb50784a9a7..30eed05a4f8b 100644 --- a/clippy_dev/src/parse.rs +++ b/clippy_dev/src/parse.rs @@ -13,6 +13,7 @@ use std::str::pattern::Pattern; pub struct ParseCxImpl<'cx> { pub arena: &'cx DroplessArena, pub str_buf: StrBuf, + pub str_list_buf: VecBuf<&'cx str>, } pub type ParseCx<'cx> = &'cx mut ParseCxImpl<'cx>; @@ -22,6 +23,7 @@ pub fn new_parse_cx<'env, T>(f: impl for<'cx> FnOnce(&'cx mut Scoped<'cx, 'env, f(&mut Scoped::new(ParseCxImpl { arena: &arena, str_buf: StrBuf::with_capacity(128), + str_list_buf: VecBuf::with_capacity(128), })) } @@ -82,6 +84,20 @@ impl StrBuf { } } +pub struct VecBuf(Vec); +impl VecBuf { + /// Creates a new buffer with the specified initial capacity. + pub fn with_capacity(cap: usize) -> Self { + Self(Vec::with_capacity(cap)) + } + + /// Performs an operation with the freshly cleared buffer. + pub fn with(&mut self, f: impl FnOnce(&mut Vec) -> R) -> R { + self.0.clear(); + f(&mut self.0) + } +} + #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum LintTool { Rustc, @@ -128,7 +144,7 @@ pub struct ActiveLint<'cx> { pub group: &'cx str, pub module: &'cx str, pub path: PathBuf, - pub declaration_range: Range, + pub declaration_range: Range, } pub struct DeprecatedLint<'cx> { @@ -147,8 +163,35 @@ pub enum Lint<'cx> { Renamed(RenamedLint<'cx>), } +#[derive(Clone, Copy)] +pub enum LintPassMac { + Declare, + Impl, +} +impl LintPassMac { + pub fn name(self) -> &'static str { + match self { + Self::Declare => "declare_lint_pass", + Self::Impl => "impl_lint_pass", + } + } +} + +pub struct LintPass<'cx> { + /// The raw text of the documentation comments. May include leading/trailing + /// whitespace and empty lines. + pub docs: &'cx str, + pub name: &'cx str, + pub lt: Option<&'cx str>, + pub mac: LintPassMac, + pub decl_range: Range, + pub lints: &'cx [&'cx str], + pub path: PathBuf, +} + pub struct LintData<'cx> { pub lints: FxHashMap<&'cx str, Lint<'cx>>, + pub lint_passes: Vec>, } impl<'cx> ParseCxImpl<'cx> { @@ -158,6 +201,7 @@ impl<'cx> ParseCxImpl<'cx> { let mut data = LintData { #[expect(clippy::default_trait_access)] lints: FxHashMap::with_capacity_and_hasher(1000, Default::default()), + lint_passes: Vec::with_capacity(400), }; let mut contents = String::new(); @@ -193,7 +237,7 @@ impl<'cx> ParseCxImpl<'cx> { self.str_buf .alloc_replaced(self.arena, path, path::MAIN_SEPARATOR, "::") }; - self.parse_clippy_lint_decls( + self.parse_lint_src_file( e.path(), File::open_read_to_cleared_string(e.path(), &mut contents), module, @@ -208,11 +252,11 @@ impl<'cx> ParseCxImpl<'cx> { } /// 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, data: &mut LintData<'cx>) { + fn parse_lint_src_file(&mut self, path: &Path, contents: &str, module: &'cx str, data: &mut LintData<'cx>) { #[allow(clippy::enum_glob_use)] use cursor::Pat::*; #[rustfmt::skip] - static DECL_TOKENS: &[cursor::Pat<'_>] = &[ + static LINT_DECL_TOKENS: &[cursor::Pat<'_>] = &[ // !{ /// docs Bang, OpenBrace, AnyComment, // #[clippy::version = "version"] @@ -220,24 +264,101 @@ impl<'cx> ParseCxImpl<'cx> { // pub NAME, GROUP, Ident("pub"), CaptureIdent, Comma, AnyComment, CaptureIdent, Comma, ]; + #[rustfmt::skip] + static PASS_DECL_TOKENS: &[cursor::Pat<'_>] = &[ + // !( NAME <'lt> => [ + Bang, OpenParen, CaptureDocLines, CaptureIdent, CaptureOptLifetimeArg, FatArrow, OpenBracket, + ]; let mut cursor = Cursor::new(contents); - 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) { - 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() - ); + let mut captures = [Capture::EMPTY; 3]; + while let Some(mac_name) = cursor.find_any_ident() { + match cursor.get_text(mac_name) { + "declare_clippy_lint" + if cursor.match_all(LINT_DECL_TOKENS, &mut captures) && cursor.find_pat(CloseBrace) => + { + 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: mac_name.pos..cursor.pos(), + }), + ) + .is_none() + ); + }, + mac @ ("declare_lint_pass" | "impl_lint_pass") if cursor.match_all(PASS_DECL_TOKENS, &mut captures) => { + let mac = if matches!(mac, "declare_lint_pass") { + LintPassMac::Declare + } else { + LintPassMac::Impl + }; + let docs = match cursor.get_text(captures[0]) { + "" => "", + x => self.arena.alloc_str(x), + }; + let name = self.arena.alloc_str(cursor.get_text(captures[1])); + let lt = cursor.get_text(captures[2]); + let lt = if lt.is_empty() { + None + } else { + Some(self.arena.alloc_str(lt)) + }; + + let lints = self.str_list_buf.with(|buf| { + // Parses a comma separated list of paths and converts each path + // to a string with whitespace removed. + while !cursor.match_pat(CloseBracket) { + buf.push(self.str_buf.with(|buf| { + if cursor.match_pat(DoubleColon) { + buf.push_str("::"); + } + let capture = cursor.capture_ident()?; + buf.push_str(cursor.get_text(capture)); + while cursor.match_pat(DoubleColon) { + buf.push_str("::"); + let capture = cursor.capture_ident()?; + buf.push_str(cursor.get_text(capture)); + } + Some(self.arena.alloc_str(buf)) + })?); + + if !cursor.match_pat(Comma) { + if !cursor.match_pat(CloseBracket) { + return None; + } + break; + } + } + + // The arena panics when allocating a size of zero. + Some(if buf.is_empty() { + &[] + } else { + buf.sort_unstable(); + &*self.arena.alloc_slice(buf) + }) + }); + + if let Some(lints) = lints + && cursor.match_all(&[CloseParen, Semi], &mut []) + { + data.lint_passes.push(LintPass { + docs, + name, + lt, + mac, + decl_range: mac_name.pos..cursor.pos(), + lints, + path: path.into(), + }); + } + }, + _ => {}, } } } diff --git a/clippy_dev/src/parse/cursor.rs b/clippy_dev/src/parse/cursor.rs index 2c142af4883a..af840532c27b 100644 --- a/clippy_dev/src/parse/cursor.rs +++ b/clippy_dev/src/parse/cursor.rs @@ -12,6 +12,7 @@ pub enum Pat<'a> { /// Matches any number of comments and doc comments. AnyComment, Ident(&'a str), + CaptureDocLines, CaptureIdent, LitStr, CaptureLitStr, @@ -22,12 +23,14 @@ pub enum Pat<'a> { Comma, DoubleColon, Eq, + FatArrow, Lifetime, Lt, Gt, OpenBrace, OpenBracket, OpenParen, + CaptureOptLifetimeArg, Pound, Semi, } @@ -112,6 +115,7 @@ impl<'txt> Cursor<'txt> { /// /// For each capture made by the pattern one item will be taken from the capture /// sequence with the result placed inside. + #[expect(clippy::too_many_lines)] fn match_impl(&mut self, pat: Pat<'_>, captures: &mut slice::IterMut<'_, Capture>) -> bool { loop { match (pat, self.next_token.kind) { @@ -121,7 +125,6 @@ impl<'txt> Cursor<'txt> { Pat::AnyComment, TokenKind::BlockComment { terminated: true, .. } | TokenKind::LineComment { .. }, ) => self.step(), - (Pat::AnyComment, _) => return true, (Pat::Bang, TokenKind::Bang) | (Pat::CloseBrace, TokenKind::CloseBrace) | (Pat::CloseBracket, TokenKind::CloseBracket) @@ -152,12 +155,48 @@ impl<'txt> Cursor<'txt> { }, (Pat::DoubleColon, TokenKind::Colon) => { self.step(); - if !self.at_end() && matches!(self.next_token.kind, TokenKind::Colon) { + if matches!(self.next_token.kind, TokenKind::Colon) { + self.step(); + return true; + } + return false; + }, + (Pat::FatArrow, TokenKind::Eq) => { + self.step(); + if matches!(self.next_token.kind, TokenKind::Gt) { self.step(); return true; } return false; }, + (Pat::CaptureOptLifetimeArg, TokenKind::Lt) => { + self.step(); + loop { + match self.next_token.kind { + TokenKind::Lifetime { .. } => break, + TokenKind::Whitespace => self.step(), + _ => return false, + } + } + *captures.next().unwrap() = Capture { + pos: self.pos, + len: self.next_token.len, + }; + self.step(); + loop { + match self.next_token.kind { + TokenKind::Gt => break, + TokenKind::Whitespace => self.step(), + _ => return false, + } + } + self.step(); + return true; + }, + (Pat::CaptureOptLifetimeArg, _) => { + *captures.next().unwrap() = Capture { pos: 0, len: 0 }; + return true; + }, #[rustfmt::skip] ( Pat::CaptureLitStr, @@ -173,6 +212,28 @@ impl<'txt> Cursor<'txt> { self.step(); return true; }, + (Pat::CaptureDocLines, TokenKind::LineComment { doc_style: Some(_) }) => { + let pos = self.pos; + loop { + self.step(); + if !matches!( + self.next_token.kind, + TokenKind::Whitespace | TokenKind::LineComment { doc_style: Some(_) } + ) { + break; + } + } + *captures.next().unwrap() = Capture { + pos, + len: self.pos - pos, + }; + return true; + }, + (Pat::CaptureDocLines, _) => { + *captures.next().unwrap() = Capture::EMPTY; + return true; + }, + (Pat::AnyComment, _) => return true, _ => return false, } } @@ -219,8 +280,8 @@ impl<'txt> Cursor<'txt> { } } - /// Consume the returns the position of the next non-whitespace token if it's an - /// identifier. Returns `None` otherwise. + /// Consume the returns the position of the next non-whitespace token if it's the + /// specified identifier. Returns `None` otherwise. pub fn match_ident(&mut self, s: &str) -> Option { loop { match self.next_token.kind { @@ -235,6 +296,23 @@ impl<'txt> Cursor<'txt> { } } + /// Consumes and captures the next non-whitespace token if it's an identifier. Returns + /// `None` otherwise. + pub fn capture_ident(&mut self) -> Option { + loop { + match self.next_token.kind { + TokenKind::Ident => { + let pos = self.pos; + let len = self.next_token.len; + self.step(); + return Some(Capture { pos, len }); + }, + TokenKind::Whitespace => self.step(), + _ => return None, + } + } + } + /// Continually attempt to match the pattern on subsequent tokens until a match is /// found. Returns whether the pattern was successfully matched. /// diff --git a/clippy_dev/src/utils.rs b/clippy_dev/src/utils.rs index 52452dd86b49..98a3458d6c2a 100644 --- a/clippy_dev/src/utils.rs +++ b/clippy_dev/src/utils.rs @@ -600,3 +600,27 @@ pub fn walk_dir_no_dot_or_target(p: impl AsRef) -> impl Iterator( + slice: &'a [T], + split_idx: impl FnMut(&'a T, &'a [T]) -> usize, +) -> impl Iterator { + struct I<'a, T, F> { + slice: &'a [T], + split_idx: F, + } + impl<'a, T, F: FnMut(&'a T, &'a [T]) -> usize> Iterator for I<'a, T, F> { + type Item = &'a [T]; + fn next(&mut self) -> Option { + let (head, tail) = self.slice.split_first()?; + if let Some((head, tail)) = self.slice.split_at_checked((self.split_idx)(head, tail) + 1) { + self.slice = tail; + Some(head) + } else { + self.slice = &[]; + None + } + } + } + I { slice, split_idx } +} diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index fa2951d91934..694b6625ffaf 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -482,10 +482,7 @@ pub struct Attributes { msrv: Msrv, } -impl_lint_pass!(Attributes => [ - INLINE_ALWAYS, - REPR_PACKED_WITHOUT_ABI, -]); +impl_lint_pass!(Attributes => [INLINE_ALWAYS, REPR_PACKED_WITHOUT_ABI]); impl Attributes { pub fn new(conf: &'static Conf) -> Self { @@ -531,8 +528,8 @@ impl EarlyAttributes { impl_lint_pass!(EarlyAttributes => [ DEPRECATED_CFG_ATTR, - NON_MINIMAL_CFG, DEPRECATED_CLIPPY_CFG_ATTR, + NON_MINIMAL_CFG, UNNECESSARY_CLIPPY_CFG, ]); @@ -561,13 +558,13 @@ impl PostExpansionEarlyAttributes { impl_lint_pass!(PostExpansionEarlyAttributes => [ ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON, + BLANKET_CLIPPY_RESTRICTION_LINTS, DEPRECATED_SEMVER, + DUPLICATED_ATTRIBUTES, IGNORE_WITHOUT_REASON, - USELESS_ATTRIBUTE, - BLANKET_CLIPPY_RESTRICTION_LINTS, - SHOULD_PANIC_WITHOUT_EXPECT, MIXED_ATTRIBUTES_STYLE, - DUPLICATED_ATTRIBUTES, + SHOULD_PANIC_WITHOUT_EXPECT, + USELESS_ATTRIBUTE, ]); impl EarlyLintPass for PostExpansionEarlyAttributes { diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 31cc004f6855..2d61c5e0b78a 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -171,7 +171,11 @@ declare_clippy_lint! { "holding a type across an await point which is not allowed to be held as per the configuration" } -impl_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF, AWAIT_HOLDING_INVALID_TYPE]); +impl_lint_pass!(AwaitHolding => [ + AWAIT_HOLDING_INVALID_TYPE, + AWAIT_HOLDING_LOCK, + AWAIT_HOLDING_REFCELL_REF, +]); pub struct AwaitHolding { def_ids: DefIdMap<(&'static str, &'static DisallowedPathWithoutReplacement)>, diff --git a/clippy_lints/src/cargo/mod.rs b/clippy_lints/src/cargo/mod.rs index 08d92adbacef..2fb468aed618 100644 --- a/clippy_lints/src/cargo/mod.rs +++ b/clippy_lints/src/cargo/mod.rs @@ -220,11 +220,11 @@ pub struct Cargo { impl_lint_pass!(Cargo => [ CARGO_COMMON_METADATA, - REDUNDANT_FEATURE_NAMES, - NEGATIVE_FEATURE_NAMES, + LINT_GROUPS_PRIORITY, MULTIPLE_CRATE_VERSIONS, + NEGATIVE_FEATURE_NAMES, + REDUNDANT_FEATURE_NAMES, WILDCARD_DEPENDENCIES, - LINT_GROUPS_PRIORITY, ]); impl Cargo { diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 3c9ebef73f0d..2e5e5dd252a4 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -857,34 +857,34 @@ impl Casts { } impl_lint_pass!(Casts => [ - CAST_PRECISION_LOSS, - CAST_SIGN_LOSS, + AS_POINTER_UNDERSCORE, + AS_PTR_CAST_MUT, + AS_UNDERSCORE, + BORROW_AS_PTR, + CAST_ABS_TO_UNSIGNED, + CAST_ENUM_CONSTRUCTOR, + CAST_ENUM_TRUNCATION, + CAST_LOSSLESS, + CAST_NAN_TO_INT, CAST_POSSIBLE_TRUNCATION, CAST_POSSIBLE_WRAP, - CAST_LOSSLESS, + CAST_PRECISION_LOSS, CAST_PTR_ALIGNMENT, + CAST_SIGN_LOSS, CAST_SLICE_DIFFERENT_SIZES, - UNNECESSARY_CAST, - FN_TO_NUMERIC_CAST_ANY, + CAST_SLICE_FROM_RAW_PARTS, + CHAR_LIT_AS_U8, + CONFUSING_METHOD_TO_NUMERIC_CAST, FN_TO_NUMERIC_CAST, + FN_TO_NUMERIC_CAST_ANY, FN_TO_NUMERIC_CAST_WITH_TRUNCATION, - CHAR_LIT_AS_U8, + MANUAL_DANGLING_PTR, + NEEDLESS_TYPE_CAST, PTR_AS_PTR, PTR_CAST_CONSTNESS, - CAST_ENUM_TRUNCATION, - CAST_ENUM_CONSTRUCTOR, - CAST_ABS_TO_UNSIGNED, - AS_UNDERSCORE, - BORROW_AS_PTR, - CAST_SLICE_FROM_RAW_PARTS, - AS_PTR_CAST_MUT, - CAST_NAN_TO_INT, - ZERO_PTR, REF_AS_PTR, - AS_POINTER_UNDERSCORE, - MANUAL_DANGLING_PTR, - CONFUSING_METHOD_TO_NUMERIC_CAST, - NEEDLESS_TYPE_CAST, + UNNECESSARY_CAST, + ZERO_PTR, ]); impl<'tcx> LateLintPass<'tcx> for Casts { diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 17e11b8b281d..0f3ef054b865 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -259,7 +259,7 @@ impl CollapsibleIf { } } -impl_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF, COLLAPSIBLE_ELSE_IF]); +impl_lint_pass!(CollapsibleIf => [COLLAPSIBLE_ELSE_IF, COLLAPSIBLE_IF]); impl LateLintPass<'_> for CollapsibleIf { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index 641f8ae03b72..95f0afcc3d88 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -45,7 +45,9 @@ declare_clippy_lint! { complexity, "unit structs can be constructed without calling `default`" } -declare_lint_pass!(DefaultConstructedUnitStructs => [DEFAULT_CONSTRUCTED_UNIT_STRUCTS]); +declare_lint_pass!(DefaultConstructedUnitStructs => [ + DEFAULT_CONSTRUCTED_UNIT_STRUCTS, +]); fn is_alias(ty: hir::Ty<'_>) -> bool { if let hir::TyKind::Path(ref qpath) = ty.kind { diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 32fd4afb122e..8ad5d40b2dc7 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -144,10 +144,10 @@ declare_clippy_lint! { } impl_lint_pass!(Dereferencing<'_> => [ + EXPLICIT_AUTO_DEREF, EXPLICIT_DEREF_METHODS, NEEDLESS_BORROW, REF_BINDING_TO_REFERENCE, - EXPLICIT_AUTO_DEREF, ]); #[derive(Default)] diff --git a/clippy_lints/src/derive/mod.rs b/clippy_lints/src/derive/mod.rs index 86614201c406..a18c7533196e 100644 --- a/clippy_lints/src/derive/mod.rs +++ b/clippy_lints/src/derive/mod.rs @@ -185,11 +185,11 @@ declare_clippy_lint! { } declare_lint_pass!(Derive => [ - EXPL_IMPL_CLONE_ON_COPY, DERIVED_HASH_WITH_MANUAL_EQ, DERIVE_ORD_XOR_PARTIAL_ORD, + DERIVE_PARTIAL_EQ_WITHOUT_EQ, + EXPL_IMPL_CLONE_ON_COPY, UNSAFE_DERIVE_DESERIALIZE, - DERIVE_PARTIAL_EQ_WITHOUT_EQ ]); impl<'tcx> LateLintPass<'tcx> for Derive { diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 0a2871f23964..3863e6d4a681 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -719,26 +719,26 @@ impl Documentation { } impl_lint_pass!(Documentation => [ + DOC_BROKEN_LINK, + DOC_COMMENT_DOUBLE_SPACE_LINEBREAKS, + DOC_INCLUDE_WITHOUT_CFG, + DOC_LAZY_CONTINUATION, DOC_LINK_CODE, DOC_LINK_WITH_QUOTES, - DOC_BROKEN_LINK, DOC_MARKDOWN, DOC_NESTED_REFDEFS, - MISSING_SAFETY_DOC, + DOC_OVERINDENTED_LIST_ITEMS, + DOC_PARAGRAPHS_MISSING_PUNCTUATION, + DOC_SUSPICIOUS_FOOTNOTES, + EMPTY_DOCS, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, + MISSING_SAFETY_DOC, NEEDLESS_DOCTEST_MAIN, - TEST_ATTR_IN_DOCTEST, - UNNECESSARY_SAFETY_DOC, SUSPICIOUS_DOC_COMMENTS, - EMPTY_DOCS, - DOC_LAZY_CONTINUATION, - DOC_OVERINDENTED_LIST_ITEMS, + TEST_ATTR_IN_DOCTEST, TOO_LONG_FIRST_DOC_PARAGRAPH, - DOC_INCLUDE_WITHOUT_CFG, - DOC_COMMENT_DOUBLE_SPACE_LINEBREAKS, - DOC_SUSPICIOUS_FOOTNOTES, - DOC_PARAGRAPHS_MISSING_PUNCTUATION, + UNNECESSARY_SAFETY_DOC, ]); impl EarlyLintPass for Documentation { diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 3bb8c484ceec..db7414559769 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -75,11 +75,7 @@ const DROP_NON_DROP_SUMMARY: &str = "call to `std::mem::drop` with a value that const FORGET_NON_DROP_SUMMARY: &str = "call to `std::mem::forget` with a value that does not implement `Drop`. \ Forgetting such a type is the same as dropping it"; -declare_lint_pass!(DropForgetRef => [ - DROP_NON_DROP, - FORGET_NON_DROP, - MEM_FORGET, -]); +declare_lint_pass!(DropForgetRef => [DROP_NON_DROP, FORGET_NON_DROP, MEM_FORGET]); impl<'tcx> LateLintPass<'tcx> for DropForgetRef { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/empty_line_after.rs b/clippy_lints/src/empty_line_after.rs index 76e67b1154be..e3453c7be1d7 100644 --- a/clippy_lints/src/empty_line_after.rs +++ b/clippy_lints/src/empty_line_after.rs @@ -101,8 +101,8 @@ pub struct EmptyLineAfter { } impl_lint_pass!(EmptyLineAfter => [ - EMPTY_LINE_AFTER_OUTER_ATTR, EMPTY_LINE_AFTER_DOC_COMMENTS, + EMPTY_LINE_AFTER_OUTER_ATTR, ]); impl EmptyLineAfter { diff --git a/clippy_lints/src/empty_with_brackets.rs b/clippy_lints/src/empty_with_brackets.rs index 7e335d5c9809..c2d205010326 100644 --- a/clippy_lints/src/empty_with_brackets.rs +++ b/clippy_lints/src/empty_with_brackets.rs @@ -90,7 +90,10 @@ pub struct EmptyWithBrackets { empty_tuple_enum_variants: FxIndexMap, } -impl_lint_pass!(EmptyWithBrackets => [EMPTY_STRUCTS_WITH_BRACKETS, EMPTY_ENUM_VARIANTS_WITH_BRACKETS]); +impl_lint_pass!(EmptyWithBrackets => [ + EMPTY_ENUM_VARIANTS_WITH_BRACKETS, + EMPTY_STRUCTS_WITH_BRACKETS, +]); impl LateLintPass<'_> for EmptyWithBrackets { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { diff --git a/clippy_lints/src/endian_bytes.rs b/clippy_lints/src/endian_bytes.rs index 75db923b1c37..37a645756217 100644 --- a/clippy_lints/src/endian_bytes.rs +++ b/clippy_lints/src/endian_bytes.rs @@ -63,7 +63,11 @@ declare_clippy_lint! { "disallows usage of the `to_be_bytes` method" } -declare_lint_pass!(EndianBytes => [HOST_ENDIAN_BYTES, LITTLE_ENDIAN_BYTES, BIG_ENDIAN_BYTES]); +declare_lint_pass!(EndianBytes => [ + BIG_ENDIAN_BYTES, + HOST_ENDIAN_BYTES, + LITTLE_ENDIAN_BYTES, +]); const HOST_NAMES: [Symbol; 2] = [sym::from_ne_bytes, sym::to_ne_bytes]; const LITTLE_NAMES: [Symbol; 2] = [sym::from_le_bytes, sym::to_le_bytes]; diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 3e46c370fb70..b5781441bce6 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -66,7 +66,10 @@ declare_clippy_lint! { "redundant closures for method calls" } -declare_lint_pass!(EtaReduction => [REDUNDANT_CLOSURE, REDUNDANT_CLOSURE_FOR_METHOD_CALLS]); +declare_lint_pass!(EtaReduction => [ + REDUNDANT_CLOSURE, + REDUNDANT_CLOSURE_FOR_METHOD_CALLS, +]); impl<'tcx> LateLintPass<'tcx> for EtaReduction { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs index 686dc5c3c4fc..fdcb013bb71e 100644 --- a/clippy_lints/src/excessive_bools.rs +++ b/clippy_lints/src/excessive_bools.rs @@ -102,7 +102,10 @@ impl ExcessiveBools { } } -impl_lint_pass!(ExcessiveBools => [STRUCT_EXCESSIVE_BOOLS, FN_PARAMS_EXCESSIVE_BOOLS]); +impl_lint_pass!(ExcessiveBools => [ + FN_PARAMS_EXCESSIVE_BOOLS, + STRUCT_EXCESSIVE_BOOLS, +]); fn has_n_bools<'tcx>(iter: impl Iterator>, mut count: u64) -> bool { iter.filter(|ty| is_bool(ty)).any(|_| { diff --git a/clippy_lints/src/field_scoped_visibility_modifiers.rs b/clippy_lints/src/field_scoped_visibility_modifiers.rs index dfb0b4f103c5..4b736c68cb86 100644 --- a/clippy_lints/src/field_scoped_visibility_modifiers.rs +++ b/clippy_lints/src/field_scoped_visibility_modifiers.rs @@ -47,7 +47,9 @@ declare_clippy_lint! { "checks for usage of a scoped visibility modifier, like `pub(crate)`, on fields" } -declare_lint_pass!(FieldScopedVisibilityModifiers => [FIELD_SCOPED_VISIBILITY_MODIFIERS]); +declare_lint_pass!(FieldScopedVisibilityModifiers => [ + FIELD_SCOPED_VISIBILITY_MODIFIERS, +]); impl EarlyLintPass for FieldScopedVisibilityModifiers { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 6178addfff12..630291e4d836 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -65,9 +65,7 @@ pub struct FloatLiteral { const_literal_digits_threshold: usize, } -impl_lint_pass!(FloatLiteral => [ - EXCESSIVE_PRECISION, LOSSY_FLOAT_LITERAL -]); +impl_lint_pass!(FloatLiteral => [EXCESSIVE_PRECISION, LOSSY_FLOAT_LITERAL]); impl FloatLiteral { pub fn new(conf: &'static Conf) -> Self { diff --git a/clippy_lints/src/floating_point_arithmetic/mod.rs b/clippy_lints/src/floating_point_arithmetic/mod.rs index edc638c96bbf..0833761b32dc 100644 --- a/clippy_lints/src/floating_point_arithmetic/mod.rs +++ b/clippy_lints/src/floating_point_arithmetic/mod.rs @@ -103,10 +103,7 @@ declare_clippy_lint! { "usage of sub-optimal floating point operations" } -declare_lint_pass!(FloatingPointArithmetic => [ - IMPRECISE_FLOPS, - SUBOPTIMAL_FLOPS -]); +declare_lint_pass!(FloatingPointArithmetic => [IMPRECISE_FLOPS, SUBOPTIMAL_FLOPS]); impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 3eb358917a0e..dfcae1c85ef9 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -260,12 +260,12 @@ declare_clippy_lint! { impl_lint_pass!(FormatArgs<'_> => [ FORMAT_IN_FORMAT_ARGS, + POINTER_FORMAT, TO_STRING_IN_FORMAT_ARGS, UNINLINED_FORMAT_ARGS, UNNECESSARY_DEBUG_FORMATTING, - UNUSED_FORMAT_SPECS, - POINTER_FORMAT, UNNECESSARY_TRAILING_COMMA, + UNUSED_FORMAT_SPECS, ]); #[expect(clippy::struct_field_names)] diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index 903d43e56c4b..744d087f4e0f 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -113,7 +113,7 @@ impl FormatImpl { } } -impl_lint_pass!(FormatImpl => [RECURSIVE_FORMAT_IMPL, PRINT_IN_FORMAT_IMPL]); +impl_lint_pass!(FormatImpl => [PRINT_IN_FORMAT_IMPL, RECURSIVE_FORMAT_IMPL]); impl<'tcx> LateLintPass<'tcx> for FormatImpl { fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 7a64d3135fa5..4bedbd378bf5 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -138,11 +138,11 @@ declare_clippy_lint! { } declare_lint_pass!(Formatting => [ + POSSIBLE_MISSING_COMMA, + POSSIBLE_MISSING_ELSE, SUSPICIOUS_ASSIGNMENT_FORMATTING, - SUSPICIOUS_UNARY_OP_FORMATTING, SUSPICIOUS_ELSE_FORMATTING, - POSSIBLE_MISSING_ELSE, - POSSIBLE_MISSING_COMMA + SUSPICIOUS_UNARY_OP_FORMATTING, ]); impl EarlyLintPass for Formatting { diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 9a7427ea1447..0a3af59e1f7f 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -516,18 +516,18 @@ impl Functions { } impl_lint_pass!(Functions => [ - TOO_MANY_ARGUMENTS, - TOO_MANY_LINES, - NOT_UNSAFE_PTR_ARG_DEREF, - MUST_USE_UNIT, DOUBLE_MUST_USE, - MUST_USE_CANDIDATE, - RESULT_UNIT_ERR, - RESULT_LARGE_ERR, - MISNAMED_GETTERS, IMPL_TRAIT_IN_PARAMS, - RENAMED_FUNCTION_PARAMS, + MISNAMED_GETTERS, + MUST_USE_CANDIDATE, + MUST_USE_UNIT, + NOT_UNSAFE_PTR_ARG_DEREF, REF_OPTION, + RENAMED_FUNCTION_PARAMS, + RESULT_LARGE_ERR, + RESULT_UNIT_ERR, + TOO_MANY_ARGUMENTS, + TOO_MANY_LINES, ]); impl<'tcx> LateLintPass<'tcx> for Functions { diff --git a/clippy_lints/src/ifs/mod.rs b/clippy_lints/src/ifs/mod.rs index 739f2fc91729..fa17685c1698 100644 --- a/clippy_lints/src/ifs/mod.rs +++ b/clippy_lints/src/ifs/mod.rs @@ -160,10 +160,10 @@ impl<'tcx> CopyAndPaste<'tcx> { } impl_lint_pass!(CopyAndPaste<'_> => [ + BRANCHES_SHARING_CODE, IFS_SAME_COND, - SAME_FUNCTIONS_IN_IF_CONDITION, IF_SAME_THEN_ELSE, - BRANCHES_SHARING_CODE + SAME_FUNCTIONS_IN_IF_CONDITION, ]); impl<'tcx> LateLintPass<'tcx> for CopyAndPaste<'tcx> { diff --git a/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs b/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs index f73182d3af0d..dec08d94e89d 100644 --- a/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs +++ b/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs @@ -69,7 +69,9 @@ declare_clippy_lint! { "ensures that the semantics of `Borrow` for `Hash` are satisfied when `Borrow` and `Borrow<[u8]>` are implemented" } -declare_lint_pass!(ImplHashWithBorrowStrBytes => [IMPL_HASH_BORROW_WITH_STR_AND_BYTES]); +declare_lint_pass!(ImplHashWithBorrowStrBytes => [ + IMPL_HASH_BORROW_WITH_STR_AND_BYTES, +]); impl LateLintPass<'_> for ImplHashWithBorrowStrBytes { /// We are emitting this lint at the Hash impl of a type that implements all diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 516f9e3aa60c..a7ee6474242b 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -83,7 +83,10 @@ pub struct ImplicitSaturatingSub { msrv: Msrv, } -impl_lint_pass!(ImplicitSaturatingSub => [IMPLICIT_SATURATING_SUB, INVERTED_SATURATING_SUB]); +impl_lint_pass!(ImplicitSaturatingSub => [ + IMPLICIT_SATURATING_SUB, + INVERTED_SATURATING_SUB, +]); impl ImplicitSaturatingSub { pub fn new(conf: &'static Conf) -> Self { diff --git a/clippy_lints/src/inconsistent_struct_constructor.rs b/clippy_lints/src/inconsistent_struct_constructor.rs index e6129757e560..60cc1da3eee2 100644 --- a/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/clippy_lints/src/inconsistent_struct_constructor.rs @@ -76,7 +76,9 @@ impl InconsistentStructConstructor { } } -impl_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRUCTOR]); +impl_lint_pass!(InconsistentStructConstructor => [ + INCONSISTENT_STRUCT_CONSTRUCTOR, +]); impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index e569a5c7b612..22082646eb31 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -88,7 +88,10 @@ declare_clippy_lint! { "type implements inherent method `to_string()`, which gets shadowed by the implementation of the `Display` trait" } -declare_lint_pass!(InherentToString => [INHERENT_TO_STRING, INHERENT_TO_STRING_SHADOW_DISPLAY]); +declare_lint_pass!(InherentToString => [ + INHERENT_TO_STRING, + INHERENT_TO_STRING_SHADOW_DISPLAY, +]); impl<'tcx> LateLintPass<'tcx> for InherentToString { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs index 22767901614e..1727b5934a6a 100644 --- a/clippy_lints/src/item_name_repetitions.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -197,9 +197,9 @@ impl ItemNameRepetitions { impl_lint_pass!(ItemNameRepetitions => [ ENUM_VARIANT_NAMES, - STRUCT_FIELD_NAMES, + MODULE_INCEPTION, MODULE_NAME_REPETITIONS, - MODULE_INCEPTION + STRUCT_FIELD_NAMES, ]); #[must_use] diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs index 645e0f981f27..89f8ede06bb3 100644 --- a/clippy_lints/src/iter_without_into_iter.rs +++ b/clippy_lints/src/iter_without_into_iter.rs @@ -105,7 +105,10 @@ declare_clippy_lint! { "implementing `IntoIterator for (&|&mut) Type` without an inherent `iter(_mut)` method" } -declare_lint_pass!(IterWithoutIntoIter => [ITER_WITHOUT_INTO_ITER, INTO_ITER_WITHOUT_ITER]); +declare_lint_pass!(IterWithoutIntoIter => [ + INTO_ITER_WITHOUT_ITER, + ITER_WITHOUT_INTO_ITER, +]); /// Checks if a given type is nameable in a trait (impl). /// RPIT is stable, but impl Trait in traits is not (yet), so when we have diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 2e576da38b89..9c954fe1b07d 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -93,7 +93,7 @@ pub struct LenZero { msrv: Msrv, } -impl_lint_pass!(LenZero => [LEN_ZERO, COMPARISON_TO_EMPTY]); +impl_lint_pass!(LenZero => [COMPARISON_TO_EMPTY, LEN_ZERO]); impl LenZero { pub fn new(conf: &'static Conf) -> Self { diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index b72e14246db7..ff6ba3ea1623 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -127,7 +127,12 @@ declare_clippy_lint! { "non-binding `let` without a type annotation" } -declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_FUTURE, LET_UNDERSCORE_UNTYPED]); +declare_lint_pass!(LetUnderscore => [ + LET_UNDERSCORE_FUTURE, + LET_UNDERSCORE_LOCK, + LET_UNDERSCORE_MUST_USE, + LET_UNDERSCORE_UNTYPED, +]); impl<'tcx> LateLintPass<'tcx> for LetUnderscore { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) { diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 679fb983d532..d9008eee25d2 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -135,9 +135,9 @@ impl Lifetimes { } impl_lint_pass!(Lifetimes => [ - NEEDLESS_LIFETIMES, ELIDABLE_LIFETIME_NAMES, EXTRA_UNUSED_LIFETIMES, + NEEDLESS_LIFETIMES, ]); impl<'tcx> LateLintPass<'tcx> for Lifetimes { diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 7cbfa2d097ae..1dd3a042e3bf 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -196,10 +196,10 @@ pub struct LiteralDigitGrouping { } impl_lint_pass!(LiteralDigitGrouping => [ - UNREADABLE_LITERAL, INCONSISTENT_DIGIT_GROUPING, LARGE_DIGIT_GROUPS, MISTYPED_LITERAL_SUFFIXES, + UNREADABLE_LITERAL, UNUSUAL_BYTE_GROUPINGS, ]); diff --git a/clippy_lints/src/literal_string_with_formatting_args.rs b/clippy_lints/src/literal_string_with_formatting_args.rs index 244e7c95122e..2751a7edc1ae 100644 --- a/clippy_lints/src/literal_string_with_formatting_args.rs +++ b/clippy_lints/src/literal_string_with_formatting_args.rs @@ -36,7 +36,9 @@ declare_clippy_lint! { "Checks if string literals have formatting arguments" } -declare_lint_pass!(LiteralStringWithFormattingArg => [LITERAL_STRING_WITH_FORMATTING_ARGS]); +declare_lint_pass!(LiteralStringWithFormattingArg => [ + LITERAL_STRING_WITH_FORMATTING_ARGS, +]); fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, spans: &[(Span, Option)]) { if !spans.is_empty() diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index 83574cab6b67..0b69538c063f 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -799,30 +799,30 @@ impl Loops { } impl_lint_pass!(Loops => [ - MANUAL_MEMCPY, - MANUAL_FLATTEN, - NEEDLESS_RANGE_LOOP, - EXPLICIT_ITER_LOOP, - EXPLICIT_INTO_ITER_LOOP, - ITER_NEXT_LOOP, - WHILE_LET_LOOP, - EXPLICIT_COUNTER_LOOP, + CHAR_INDICES_AS_BYTE_INDICES, EMPTY_LOOP, - WHILE_LET_ON_ITERATOR, + EXPLICIT_COUNTER_LOOP, + EXPLICIT_INTO_ITER_LOOP, + EXPLICIT_ITER_LOOP, FOR_KV_MAP, - NEVER_LOOP, + INFINITE_LOOP, + ITER_NEXT_LOOP, + MANUAL_FIND, + MANUAL_FLATTEN, + MANUAL_MEMCPY, + MANUAL_SLICE_FILL, + MANUAL_WHILE_LET_SOME, + MISSING_SPIN_LOOP, MUT_RANGE_BOUND, - WHILE_IMMUTABLE_CONDITION, - WHILE_FLOAT, + NEEDLESS_RANGE_LOOP, + NEVER_LOOP, SAME_ITEM_PUSH, SINGLE_ELEMENT_LOOP, - MISSING_SPIN_LOOP, - MANUAL_FIND, - MANUAL_WHILE_LET_SOME, UNUSED_ENUMERATE_INDEX, - INFINITE_LOOP, - MANUAL_SLICE_FILL, - CHAR_INDICES_AS_BYTE_INDICES, + WHILE_FLOAT, + WHILE_IMMUTABLE_CONDITION, + WHILE_LET_LOOP, + WHILE_LET_ON_ITERATOR, ]); impl<'tcx> LateLintPass<'tcx> for Loops { diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index a81c4dc6a793..6914c88323ac 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -61,7 +61,7 @@ declare_clippy_lint! { style, "use dedicated method to check if a float is finite" } -impl_lint_pass!(ManualFloatMethods => [MANUAL_IS_INFINITE, MANUAL_IS_FINITE]); +impl_lint_pass!(ManualFloatMethods => [MANUAL_IS_FINITE, MANUAL_IS_INFINITE]); #[derive(Clone, Copy)] enum Variant { diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 6f49c5524118..aeffbb26722f 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -1021,33 +1021,33 @@ impl Matches { } impl_lint_pass!(Matches => [ - SINGLE_MATCH, - MATCH_REF_PATS, - MATCH_BOOL, - SINGLE_MATCH_ELSE, - MATCH_OVERLAPPING_ARM, - MATCH_WILD_ERR_ARM, - MATCH_AS_REF, - WILDCARD_ENUM_MATCH_ARM, - MATCH_WILDCARD_FOR_SINGLE_VARIANTS, - WILDCARD_IN_OR_PATTERNS, - MATCH_SINGLE_BINDING, - INFALLIBLE_DESTRUCTURING_MATCH, - REST_PAT_IN_FULLY_BOUND_STRUCTS, - REDUNDANT_PATTERN_MATCHING, - MATCH_LIKE_MATCHES_MACRO, - MATCH_SAME_ARMS, - NEEDLESS_MATCH, COLLAPSIBLE_MATCH, + INFALLIBLE_DESTRUCTURING_MATCH, + MANUAL_FILTER, + MANUAL_MAP, + MANUAL_OK_ERR, MANUAL_UNWRAP_OR, MANUAL_UNWRAP_OR_DEFAULT, + MATCH_AS_REF, + MATCH_BOOL, + MATCH_LIKE_MATCHES_MACRO, + MATCH_OVERLAPPING_ARM, + MATCH_REF_PATS, + MATCH_SAME_ARMS, + MATCH_SINGLE_BINDING, MATCH_STR_CASE_MISMATCH, + MATCH_WILDCARD_FOR_SINGLE_VARIANTS, + MATCH_WILD_ERR_ARM, + NEEDLESS_MATCH, + REDUNDANT_GUARDS, + REDUNDANT_PATTERN_MATCHING, + REST_PAT_IN_FULLY_BOUND_STRUCTS, SIGNIFICANT_DROP_IN_SCRUTINEE, + SINGLE_MATCH, + SINGLE_MATCH_ELSE, TRY_ERR, - MANUAL_MAP, - MANUAL_FILTER, - REDUNDANT_GUARDS, - MANUAL_OK_ERR, + WILDCARD_ENUM_MATCH_ARM, + WILDCARD_IN_OR_PATTERNS, ]); impl<'tcx> LateLintPass<'tcx> for Matches { diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 0f32f89666a0..806b1553cc79 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -125,8 +125,12 @@ declare_clippy_lint! { "replacing a value of type `T` with `T::default()` instead of using `std::mem::take`" } -impl_lint_pass!(MemReplace => - [MEM_REPLACE_OPTION_WITH_NONE, MEM_REPLACE_OPTION_WITH_SOME, MEM_REPLACE_WITH_UNINIT, MEM_REPLACE_WITH_DEFAULT]); +impl_lint_pass!(MemReplace => [ + MEM_REPLACE_OPTION_WITH_NONE, + MEM_REPLACE_OPTION_WITH_SOME, + MEM_REPLACE_WITH_DEFAULT, + MEM_REPLACE_WITH_UNINIT, +]); fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) -> bool { if is_none_expr(cx, src) { diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 74db7ae03ba0..a8d912d5520c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4783,159 +4783,159 @@ impl Methods { } impl_lint_pass!(Methods => [ - UNWRAP_USED, - EXPECT_USED, - SHOULD_IMPLEMENT_TRAIT, - WRONG_SELF_CONVENTION, - OK_EXPECT, - UNWRAP_OR_DEFAULT, - MAP_UNWRAP_OR, - RESULT_MAP_OR_INTO_OPTION, - OPTION_MAP_OR_NONE, BIND_INSTEAD_OF_MAP, - OR_FUN_CALL, - OR_THEN_UNWRAP, - EXPECT_FUN_CALL, - CHARS_NEXT_CMP, + BYTES_COUNT_TO_LEN, + BYTES_NTH, + CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, CHARS_LAST_CMP, + CHARS_NEXT_CMP, + CLEAR_WITH_DRAIN, + CLONED_INSTEAD_OF_COPIED, CLONE_ON_COPY, CLONE_ON_REF_PTR, COLLAPSIBLE_STR_REPLACE, CONST_IS_EMPTY, - ITER_OVEREAGER_CLONED, - CLONED_INSTEAD_OF_COPIED, - FLAT_MAP_OPTION, - INEFFICIENT_TO_STRING, - NEW_RET_NO_SELF, - SINGLE_CHAR_ADD_STR, - SEARCH_IS_SOME, - FILTER_NEXT, - SKIP_WHILE_NEXT, + DOUBLE_ENDED_ITERATOR_LAST, + DRAIN_COLLECT, + ERR_EXPECT, + EXPECT_FUN_CALL, + EXPECT_USED, + EXTEND_WITH_DRAIN, + FILETYPE_IS_FILE, + FILTER_MAP_BOOL_THEN, FILTER_MAP_IDENTITY, - MAP_IDENTITY, - MANUAL_FILTER_MAP, - MANUAL_FIND_MAP, - OPTION_FILTER_MAP, FILTER_MAP_NEXT, + FILTER_NEXT, FLAT_MAP_IDENTITY, - MAP_FLATTEN, + FLAT_MAP_OPTION, + FORMAT_COLLECT, + FROM_ITER_INSTEAD_OF_COLLECT, + GET_FIRST, + GET_LAST_WITH_LEN, + GET_UNWRAP, + IMPLICIT_CLONE, + INEFFICIENT_TO_STRING, + INSPECT_FOR_EACH, + INTO_ITER_ON_REF, + IO_OTHER_ERROR, + IP_CONSTANT, + IS_DIGIT_ASCII_RADIX, ITERATOR_STEP_BY_ZERO, - ITER_NEXT_SLICE, + ITER_CLONED_COLLECT, ITER_COUNT, + ITER_FILTER_IS_OK, + ITER_FILTER_IS_SOME, + ITER_KV_MAP, + ITER_NEXT_SLICE, ITER_NTH, ITER_NTH_ZERO, - BYTES_NTH, + ITER_ON_EMPTY_COLLECTIONS, + ITER_ON_SINGLE_ITEMS, + ITER_OUT_OF_BOUNDS, + ITER_OVEREAGER_CLONED, ITER_SKIP_NEXT, - GET_UNWRAP, - GET_LAST_WITH_LEN, - STRING_EXTEND_CHARS, - ITER_CLONED_COLLECT, + ITER_SKIP_ZERO, ITER_WITH_DRAIN, - TYPE_ID_ON_BOX, - USELESS_ASREF, - UNNECESSARY_FOLD, - UNNECESSARY_FILTER_MAP, - UNNECESSARY_FIND_MAP, - INTO_ITER_ON_REF, - SUSPICIOUS_MAP, - UNINIT_ASSUMED_INIT, + JOIN_ABSOLUTE_PATHS, + LINES_FILTER_MAP_OK, + MANUAL_CONTAINS, + MANUAL_C_STR_LITERALS, + MANUAL_FILTER_MAP, + MANUAL_FIND_MAP, + MANUAL_INSPECT, + MANUAL_IS_VARIANT_AND, + MANUAL_NEXT_BACK, + MANUAL_OK_OR, + MANUAL_REPEAT_N, MANUAL_SATURATING_ARITHMETIC, - ZST_OFFSET, - PTR_OFFSET_BY_LITERAL, - PTR_OFFSET_WITH_CAST, - FILETYPE_IS_FILE, - OPTION_AS_REF_DEREF, - UNNECESSARY_LAZY_EVALUATIONS, - MAP_COLLECT_RESULT_UNIT, - FROM_ITER_INSTEAD_OF_COLLECT, - INSPECT_FOR_EACH, - IMPLICIT_CLONE, - SUSPICIOUS_TO_OWNED, - SUSPICIOUS_SPLITN, - MANUAL_STR_REPEAT, - EXTEND_WITH_DRAIN, MANUAL_SPLIT_ONCE, - NEEDLESS_SPLITN, - UNNECESSARY_TO_OWNED, - UNNECESSARY_JOIN, - ERR_EXPECT, - NEEDLESS_OPTION_AS_DEREF, - IS_DIGIT_ASCII_RADIX, - NEEDLESS_OPTION_TAKE, - NO_EFFECT_REPLACE, - OBFUSCATED_IF_ELSE, - ITER_ON_SINGLE_ITEMS, - ITER_ON_EMPTY_COLLECTIONS, - NAIVE_BYTECOUNT, - BYTES_COUNT_TO_LEN, - CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, - GET_FIRST, - MANUAL_OK_OR, + MANUAL_STR_REPEAT, + MANUAL_TRY_FOLD, + MAP_ALL_ANY_IDENTITY, MAP_CLONE, + MAP_COLLECT_RESULT_UNIT, MAP_ERR_IGNORE, + MAP_FLATTEN, + MAP_IDENTITY, + MAP_UNWRAP_OR, + MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES, MUT_MUTEX_LOCK, + NAIVE_BYTECOUNT, + NEEDLESS_AS_BYTES, + NEEDLESS_CHARACTER_ITERATION, + NEEDLESS_COLLECT, + NEEDLESS_OPTION_AS_DEREF, + NEEDLESS_OPTION_TAKE, + NEEDLESS_SPLITN, + NEW_RET_NO_SELF, NONSENSICAL_OPEN_OPTIONS, - SUSPICIOUS_OPEN_OPTIONS, + NO_EFFECT_REPLACE, + OBFUSCATED_IF_ELSE, + OK_EXPECT, + OPTION_AS_REF_CLONED, + OPTION_AS_REF_DEREF, + OPTION_FILTER_MAP, + OPTION_MAP_OR_NONE, + OR_FUN_CALL, + OR_THEN_UNWRAP, PATH_BUF_PUSH_OVERWRITE, + PATH_ENDS_WITH_EXT, + PTR_OFFSET_BY_LITERAL, + PTR_OFFSET_WITH_CAST, RANGE_ZIP_WITH_LEN, - REPEAT_ONCE, - STABLE_SORT_PRIMITIVE, - UNIT_HASH, + READONLY_WRITE_LOCK, READ_LINE_WITHOUT_TRIM, - UNNECESSARY_SORT_BY, - VEC_RESIZE_TO_ZERO, - VERBOSE_FILE_READS, - ITER_KV_MAP, + REDUNDANT_AS_STR, + REDUNDANT_ITER_CLONED, + REPEAT_ONCE, + RESULT_FILTER_MAP, + RESULT_MAP_OR_INTO_OPTION, + RETURN_AND_THEN, + SEARCH_IS_SOME, SEEK_FROM_CURRENT, SEEK_TO_START_INSTEAD_OF_REWIND, - NEEDLESS_COLLECT, - SUSPICIOUS_COMMAND_ARG_SPACE, - CLEAR_WITH_DRAIN, - MANUAL_NEXT_BACK, - UNNECESSARY_LITERAL_UNWRAP, - DRAIN_COLLECT, - MANUAL_TRY_FOLD, - FORMAT_COLLECT, + SHOULD_IMPLEMENT_TRAIT, + SINGLE_CHAR_ADD_STR, + SKIP_WHILE_NEXT, + SLICED_STRING_AS_BYTES, + STABLE_SORT_PRIMITIVE, + STRING_EXTEND_CHARS, STRING_LIT_CHARS_ANY, - ITER_SKIP_ZERO, - FILTER_MAP_BOOL_THEN, - READONLY_WRITE_LOCK, - ITER_OUT_OF_BOUNDS, - PATH_ENDS_WITH_EXT, - REDUNDANT_AS_STR, - WAKER_CLONE_WAKE, - UNNECESSARY_FALLIBLE_CONVERSIONS, - JOIN_ABSOLUTE_PATHS, - RESULT_FILTER_MAP, - ITER_FILTER_IS_SOME, - ITER_FILTER_IS_OK, - MANUAL_IS_VARIANT_AND, STR_SPLIT_AT_NEWLINE, - OPTION_AS_REF_CLONED, - UNNECESSARY_RESULT_MAP_OR_ELSE, - MANUAL_C_STR_LITERALS, - UNNECESSARY_GET_THEN_CHECK, + SUSPICIOUS_COMMAND_ARG_SPACE, + SUSPICIOUS_MAP, + SUSPICIOUS_OPEN_OPTIONS, + SUSPICIOUS_SPLITN, + SUSPICIOUS_TO_OWNED, + SWAP_WITH_TEMPORARY, + TYPE_ID_ON_BOX, + UNBUFFERED_BYTES, + UNINIT_ASSUMED_INIT, + UNIT_HASH, + UNNECESSARY_FALLIBLE_CONVERSIONS, + UNNECESSARY_FILTER_MAP, + UNNECESSARY_FIND_MAP, UNNECESSARY_FIRST_THEN_CHECK, - NEEDLESS_CHARACTER_ITERATION, - MANUAL_INSPECT, - UNNECESSARY_MIN_OR_MAX, - NEEDLESS_AS_BYTES, - MAP_ALL_ANY_IDENTITY, - MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES, + UNNECESSARY_FOLD, + UNNECESSARY_GET_THEN_CHECK, + UNNECESSARY_JOIN, + UNNECESSARY_LAZY_EVALUATIONS, + UNNECESSARY_LITERAL_UNWRAP, UNNECESSARY_MAP_OR, - DOUBLE_ENDED_ITERATOR_LAST, - USELESS_NONZERO_NEW_UNCHECKED, - MANUAL_REPEAT_N, - SLICED_STRING_AS_BYTES, - RETURN_AND_THEN, - UNBUFFERED_BYTES, - MANUAL_CONTAINS, - IO_OTHER_ERROR, - SWAP_WITH_TEMPORARY, - IP_CONSTANT, - REDUNDANT_ITER_CLONED, + UNNECESSARY_MIN_OR_MAX, UNNECESSARY_OPTION_MAP_OR_ELSE, - LINES_FILTER_MAP_OK, + UNNECESSARY_RESULT_MAP_OR_ELSE, + UNNECESSARY_SORT_BY, + UNNECESSARY_TO_OWNED, + UNWRAP_OR_DEFAULT, + UNWRAP_USED, + USELESS_ASREF, + USELESS_NONZERO_NEW_UNCHECKED, + VEC_RESIZE_TO_ZERO, + VERBOSE_FILE_READS, + WAKER_CLONE_WAKE, + WRONG_SELF_CONVENTION, + ZST_OFFSET, ]); /// Extracts a method call name, args, and `Span` of the method name. diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 19e9910dfe9d..0f04d90b70cf 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -94,9 +94,9 @@ declare_clippy_lint! { } declare_lint_pass!(LintPass => [ + SHORT_CIRCUIT_STATEMENT, USED_UNDERSCORE_BINDING, USED_UNDERSCORE_ITEMS, - SHORT_CIRCUIT_STATEMENT, ]); impl<'tcx> LateLintPass<'tcx> for LintPass { diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index f988323a8c13..e4a2befef77c 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -303,15 +303,15 @@ declare_clippy_lint! { } declare_lint_pass!(MiscEarlyLints => [ - UNNEEDED_FIELD_PATTERN, - MIXED_CASE_HEX_LITERALS, - UNSEPARATED_LITERAL_SUFFIX, - SEPARATED_LITERAL_SUFFIX, - ZERO_PREFIXED_LITERAL, BUILTIN_TYPE_SHADOW, + MIXED_CASE_HEX_LITERALS, + REDUNDANT_AT_REST_PATTERN, REDUNDANT_PATTERN, + SEPARATED_LITERAL_SUFFIX, + UNNEEDED_FIELD_PATTERN, UNNEEDED_WILDCARD_PATTERN, - REDUNDANT_AT_REST_PATTERN, + UNSEPARATED_LITERAL_SUFFIX, + ZERO_PREFIXED_LITERAL, ]); impl EarlyLintPass for MiscEarlyLints { diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index 53f97abe0b44..d749a8017557 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -79,7 +79,10 @@ declare_clippy_lint! { "whether an expression contains a diverging sub expression" } -declare_lint_pass!(EvalOrderDependence => [MIXED_READ_WRITE_IN_EXPRESSION, DIVERGING_SUB_EXPRESSION]); +declare_lint_pass!(EvalOrderDependence => [ + DIVERGING_SUB_EXPRESSION, + MIXED_READ_WRITE_IN_EXPRESSION, +]); impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 98a9a98d281a..e4e898362b51 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -72,7 +72,7 @@ pub struct MutableKeyType<'tcx> { interior_mut: InteriorMut<'tcx>, } -impl_lint_pass!(MutableKeyType<'_> => [ MUTABLE_KEY_TYPE ]); +impl_lint_pass!(MutableKeyType<'_> => [MUTABLE_KEY_TYPE]); impl<'tcx> LateLintPass<'tcx> for MutableKeyType<'tcx> { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { diff --git a/clippy_lints/src/needless_borrows_for_generic_args.rs b/clippy_lints/src/needless_borrows_for_generic_args.rs index 25fcc7ee568e..0f82eb80ba77 100644 --- a/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -66,7 +66,9 @@ pub struct NeedlessBorrowsForGenericArgs<'tcx> { // `IntoIterator` for arrays requires Rust 1.53. msrv: Msrv, } -impl_lint_pass!(NeedlessBorrowsForGenericArgs<'_> => [NEEDLESS_BORROWS_FOR_GENERIC_ARGS]); +impl_lint_pass!(NeedlessBorrowsForGenericArgs<'_> => [ + NEEDLESS_BORROWS_FOR_GENERIC_ARGS, +]); impl NeedlessBorrowsForGenericArgs<'_> { pub fn new(conf: &'static Conf) -> Self { diff --git a/clippy_lints/src/needless_parens_on_range_literals.rs b/clippy_lints/src/needless_parens_on_range_literals.rs index f270ba7277cb..0c23bd6b1f96 100644 --- a/clippy_lints/src/needless_parens_on_range_literals.rs +++ b/clippy_lints/src/needless_parens_on_range_literals.rs @@ -38,7 +38,9 @@ declare_clippy_lint! { "needless parenthesis on range literals can be removed" } -declare_lint_pass!(NeedlessParensOnRangeLiterals => [NEEDLESS_PARENS_ON_RANGE_LITERALS]); +declare_lint_pass!(NeedlessParensOnRangeLiterals => [ + NEEDLESS_PARENS_ON_RANGE_LITERALS, +]); fn snippet_enclosed_in_parenthesis(snippet: &str) -> bool { snippet.starts_with('(') && snippet.ends_with(')') diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index fdb8e1b475c1..8739c7546e58 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -79,7 +79,11 @@ pub struct NoEffect { local_bindings: Vec>, } -impl_lint_pass!(NoEffect => [NO_EFFECT, UNNECESSARY_OPERATION, NO_EFFECT_UNDERSCORE_BINDING]); +impl_lint_pass!(NoEffect => [ + NO_EFFECT, + NO_EFFECT_UNDERSCORE_BINDING, + UNNECESSARY_OPERATION, +]); impl<'tcx> LateLintPass<'tcx> for NoEffect { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { diff --git a/clippy_lints/src/non_canonical_impls.rs b/clippy_lints/src/non_canonical_impls.rs index e66c088617cb..f87860ec164c 100644 --- a/clippy_lints/src/non_canonical_impls.rs +++ b/clippy_lints/src/non_canonical_impls.rs @@ -108,7 +108,10 @@ declare_clippy_lint! { suspicious, "non-canonical implementation of `PartialOrd` on an `Ord` type" } -impl_lint_pass!(NonCanonicalImpls => [NON_CANONICAL_CLONE_IMPL, NON_CANONICAL_PARTIAL_ORD_IMPL]); +impl_lint_pass!(NonCanonicalImpls => [ + NON_CANONICAL_CLONE_IMPL, + NON_CANONICAL_PARTIAL_ORD_IMPL, +]); #[expect( clippy::struct_field_names, diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index e09fc0a76366..396d57f21612 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -257,7 +257,10 @@ pub struct NonCopyConst<'tcx> { freeze_tys: FxHashMap, IsFreeze>, } -impl_lint_pass!(NonCopyConst<'_> => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]); +impl_lint_pass!(NonCopyConst<'_> => [ + BORROW_INTERIOR_MUTABLE_CONST, + DECLARE_INTERIOR_MUTABLE_CONST, +]); impl<'tcx> NonCopyConst<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, conf: &'static Conf) -> Self { diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 1961ac1516da..4d43a9b6f5ee 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -77,7 +77,11 @@ pub struct NonExpressiveNames { pub single_char_binding_names_threshold: u64, } -impl_lint_pass!(NonExpressiveNames => [SIMILAR_NAMES, MANY_SINGLE_CHAR_NAMES, JUST_UNDERSCORES_AND_DIGITS]); +impl_lint_pass!(NonExpressiveNames => [ + JUST_UNDERSCORES_AND_DIGITS, + MANY_SINGLE_CHAR_NAMES, + SIMILAR_NAMES, +]); impl NonExpressiveNames { pub fn new(conf: &'static Conf) -> Self { diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs index f756f94d97b3..ae1c229711f0 100644 --- a/clippy_lints/src/only_used_in_recursion.rs +++ b/clippy_lints/src/only_used_in_recursion.rs @@ -164,7 +164,10 @@ declare_clippy_lint! { pedantic, "self receiver only used to recursively call method can be removed" } -impl_lint_pass!(OnlyUsedInRecursion => [ONLY_USED_IN_RECURSION, SELF_ONLY_USED_IN_RECURSION]); +impl_lint_pass!(OnlyUsedInRecursion => [ + ONLY_USED_IN_RECURSION, + SELF_ONLY_USED_IN_RECURSION, +]); #[derive(Clone, Copy)] enum FnKind { diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index 5b00f1b0bd13..9b70c9b17abb 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -979,35 +979,35 @@ impl Operators { impl_lint_pass!(Operators => [ ABSURD_EXTREME_COMPARISONS, ARITHMETIC_SIDE_EFFECTS, - FLOAT_ARITHMETIC, ASSIGN_OP_PATTERN, - MISREFACTORED_ASSIGN_OP, BAD_BIT_MASK, - INEFFECTIVE_BIT_MASK, - VERBOSE_BIT_MASK, + CMP_OWNED, + DECIMAL_BITWISE_OPERANDS, DOUBLE_COMPARISONS, - IMPOSSIBLE_COMPARISONS, - REDUNDANT_COMPARISONS, DURATION_SUBSEC, EQ_OP, - OP_REF, ERASING_OP, + FLOAT_ARITHMETIC, + FLOAT_CMP, + FLOAT_CMP_CONST, FLOAT_EQUALITY_WITHOUT_ABS, IDENTITY_OP, + IMPOSSIBLE_COMPARISONS, + INEFFECTIVE_BIT_MASK, INTEGER_DIVISION, INTEGER_DIVISION_REMAINDER_USED, - CMP_OWNED, - FLOAT_CMP, - FLOAT_CMP_CONST, - MODULO_ONE, + INVALID_UPCAST_COMPARISONS, + MANUAL_DIV_CEIL, + MANUAL_IS_MULTIPLE_OF, + MANUAL_MIDPOINT, + MISREFACTORED_ASSIGN_OP, MODULO_ARITHMETIC, + MODULO_ONE, NEEDLESS_BITWISE_BOOL, + OP_REF, + REDUNDANT_COMPARISONS, SELF_ASSIGNMENT, - MANUAL_MIDPOINT, - MANUAL_IS_MULTIPLE_OF, - MANUAL_DIV_CEIL, - INVALID_UPCAST_COMPARISONS, - DECIMAL_BITWISE_OPERANDS + VERBOSE_BIT_MASK, ]); impl<'tcx> LateLintPass<'tcx> for Operators { diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index 57127e9d2298..cc147a4a84bd 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -40,7 +40,7 @@ declare_clippy_lint! { "functions of type `Result<..>` that contain `panic!()` or assertion" } -declare_lint_pass!(PanicInResultFn => [PANIC_IN_RESULT_FN]); +declare_lint_pass!(PanicInResultFn => [PANIC_IN_RESULT_FN]); impl<'tcx> LateLintPass<'tcx> for PanicInResultFn { fn check_fn( diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 43db0085f2e3..4c318f4a7a0e 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -93,7 +93,7 @@ declare_clippy_lint! { "usage of the `unreachable!` macro" } -impl_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]); +impl_lint_pass!(PanicUnimplemented => [PANIC, TODO, UNIMPLEMENTED, UNREACHABLE]); impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 6e9142b22e0e..5d31c8687efc 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -237,7 +237,10 @@ impl PassByRefOrValue { } } -impl_lint_pass!(PassByRefOrValue => [TRIVIALLY_COPY_PASS_BY_REF, LARGE_TYPES_PASSED_BY_VALUE]); +impl_lint_pass!(PassByRefOrValue => [ + LARGE_TYPES_PASSED_BY_VALUE, + TRIVIALLY_COPY_PASS_BY_REF, +]); impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { diff --git a/clippy_lints/src/permissions_set_readonly_false.rs b/clippy_lints/src/permissions_set_readonly_false.rs index 68a34d459e0d..fab167667b93 100644 --- a/clippy_lints/src/permissions_set_readonly_false.rs +++ b/clippy_lints/src/permissions_set_readonly_false.rs @@ -26,7 +26,9 @@ declare_clippy_lint! { suspicious, "Checks for calls to `std::fs::Permissions.set_readonly` with argument `false`" } -declare_lint_pass!(PermissionsSetReadonlyFalse => [PERMISSIONS_SET_READONLY_FALSE]); +declare_lint_pass!(PermissionsSetReadonlyFalse => [ + PERMISSIONS_SET_READONLY_FALSE, +]); impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { diff --git a/clippy_lints/src/ptr/mod.rs b/clippy_lints/src/ptr/mod.rs index c4f40a7ffcaa..ba1ae5c1e0e0 100644 --- a/clippy_lints/src/ptr/mod.rs +++ b/clippy_lints/src/ptr/mod.rs @@ -135,7 +135,7 @@ declare_clippy_lint! { "use `std::ptr::eq` when comparing raw pointers" } -declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF, PTR_EQ]); +declare_lint_pass!(Ptr => [CMP_NULL, MUT_FROM_REF, PTR_ARG, PTR_EQ]); impl<'tcx> LateLintPass<'tcx> for Ptr { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 719f364357d3..6e286d16ef36 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -65,7 +65,7 @@ pub struct QuestionMark { inferred_ret_closure_stack: u16, } -impl_lint_pass!(QuestionMark => [QUESTION_MARK, MANUAL_LET_ELSE]); +impl_lint_pass!(QuestionMark => [MANUAL_LET_ELSE, QUESTION_MARK]); impl QuestionMark { pub fn new(conf: &'static Conf) -> Self { diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index ca0d41fca524..73fad7951ca4 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -175,10 +175,10 @@ impl Ranges { } impl_lint_pass!(Ranges => [ - RANGE_PLUS_ONE, + MANUAL_RANGE_CONTAINS, RANGE_MINUS_ONE, + RANGE_PLUS_ONE, REVERSED_EMPTY_RANGES, - MANUAL_RANGE_CONTAINS, ]); impl<'tcx> LateLintPass<'tcx> for Ranges { diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index f2cf809d6012..03ed3a4076b9 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -66,7 +66,7 @@ declare_clippy_lint! { "slicing instead of dereferencing" } -declare_lint_pass!(RedundantSlicing => [REDUNDANT_SLICING, DEREF_BY_SLICING]); +declare_lint_pass!(RedundantSlicing => [DEREF_BY_SLICING, REDUNDANT_SLICING]); static REDUNDANT_SLICING_LINT: (&Lint, &str) = (REDUNDANT_SLICING, "redundant slicing of the whole range"); static DEREF_BY_SLICING_LINT: (&Lint, &str) = (DEREF_BY_SLICING, "slicing when dereferencing would work"); diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index d1fc228f4b35..c7d200089701 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -119,7 +119,7 @@ pub struct Regex { loop_stack: Vec<(OwnerId, Span)>, } -impl_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX, REGEX_CREATION_IN_LOOPS]); +impl_lint_pass!(Regex => [INVALID_REGEX, REGEX_CREATION_IN_LOOPS, TRIVIAL_REGEX]); impl<'tcx> LateLintPass<'tcx> for Regex { fn check_crate(&mut self, cx: &LateContext<'tcx>) { diff --git a/clippy_lints/src/returns/mod.rs b/clippy_lints/src/returns/mod.rs index 47c6332b9b81..eb84582593a4 100644 --- a/clippy_lints/src/returns/mod.rs +++ b/clippy_lints/src/returns/mod.rs @@ -115,7 +115,11 @@ declare_clippy_lint! { "using a return statement like `return Err(expr)?;` where removing it would suffice" } -declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN, NEEDLESS_RETURN_WITH_QUESTION_MARK]); +declare_lint_pass!(Return => [ + LET_AND_RETURN, + NEEDLESS_RETURN, + NEEDLESS_RETURN_WITH_QUESTION_MARK, +]); impl<'tcx> LateLintPass<'tcx> for Return { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index f6083394fea5..3a45e7bd2bc8 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -111,7 +111,7 @@ pub(crate) struct Shadow { bindings: Vec<(FxHashMap>, LocalDefId)>, } -impl_lint_pass!(Shadow => [SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED]); +impl_lint_pass!(Shadow => [SHADOW_REUSE, SHADOW_SAME, SHADOW_UNRELATED]); impl<'tcx> LateLintPass<'tcx> for Shadow { fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index 143be5137038..4766057098de 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -109,7 +109,11 @@ impl StdReexports { } } -impl_lint_pass!(StdReexports => [STD_INSTEAD_OF_CORE, STD_INSTEAD_OF_ALLOC, ALLOC_INSTEAD_OF_CORE]); +impl_lint_pass!(StdReexports => [ + ALLOC_INSTEAD_OF_CORE, + STD_INSTEAD_OF_ALLOC, + STD_INSTEAD_OF_CORE, +]); #[derive(Debug)] enum LintPoint { diff --git a/clippy_lints/src/string_patterns.rs b/clippy_lints/src/string_patterns.rs index e5347bf3e8f0..4c640c2ed541 100644 --- a/clippy_lints/src/string_patterns.rs +++ b/clippy_lints/src/string_patterns.rs @@ -82,7 +82,10 @@ impl StringPatterns { } } -impl_lint_pass!(StringPatterns => [MANUAL_PATTERN_CHAR_COMPARISON, SINGLE_CHAR_PATTERN]); +impl_lint_pass!(StringPatterns => [ + MANUAL_PATTERN_CHAR_COMPARISON, + SINGLE_CHAR_PATTERN, +]); const PATTERN_METHODS: [(Symbol, usize); 22] = [ (sym::contains, 0), diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 9d3e4a6b1d92..4b237e0907a9 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -243,7 +243,10 @@ declare_clippy_lint! { // Max length a b"foo" string can take const MAX_LENGTH_BYTE_STRING_LIT: usize = 32; -declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES, STRING_FROM_UTF8_AS_BYTES]); +declare_lint_pass!(StringLitAsBytes => [ + STRING_FROM_UTF8_AS_BYTES, + STRING_LIT_AS_BYTES, +]); impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index af5e3ccb674a..9fa4d2c142b5 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -64,7 +64,9 @@ declare_clippy_lint! { "groupings of binary operations that look suspiciously like typos" } -declare_lint_pass!(SuspiciousOperationGroupings => [SUSPICIOUS_OPERATION_GROUPINGS]); +declare_lint_pass!(SuspiciousOperationGroupings => [ + SUSPICIOUS_OPERATION_GROUPINGS, +]); impl EarlyLintPass for SuspiciousOperationGroupings { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { diff --git a/clippy_lints/src/suspicious_trait_impl.rs b/clippy_lints/src/suspicious_trait_impl.rs index edb7600b7c06..694f1896a4d2 100644 --- a/clippy_lints/src/suspicious_trait_impl.rs +++ b/clippy_lints/src/suspicious_trait_impl.rs @@ -53,7 +53,10 @@ declare_clippy_lint! { "suspicious use of operators in impl of OpAssign trait" } -declare_lint_pass!(SuspiciousImpl => [SUSPICIOUS_ARITHMETIC_IMPL, SUSPICIOUS_OP_ASSIGN_IMPL]); +declare_lint_pass!(SuspiciousImpl => [ + SUSPICIOUS_ARITHMETIC_IMPL, + SUSPICIOUS_OP_ASSIGN_IMPL, +]); impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index c3cb2c09752f..66fdda46d060 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -75,7 +75,7 @@ declare_clippy_lint! { "`foo = bar; bar = foo` sequence" } -declare_lint_pass!(Swap => [MANUAL_SWAP, ALMOST_SWAPPED]); +declare_lint_pass!(Swap => [ALMOST_SWAPPED, MANUAL_SWAP]); impl<'tcx> LateLintPass<'tcx> for Swap { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { diff --git a/clippy_lints/src/time_subtraction.rs b/clippy_lints/src/time_subtraction.rs index 457a8f48f7e2..aca8664ba10e 100644 --- a/clippy_lints/src/time_subtraction.rs +++ b/clippy_lints/src/time_subtraction.rs @@ -83,7 +83,10 @@ impl UncheckedTimeSubtraction { } } -impl_lint_pass!(UncheckedTimeSubtraction => [MANUAL_INSTANT_ELAPSED, UNCHECKED_TIME_SUBTRACTION]); +impl_lint_pass!(UncheckedTimeSubtraction => [ + MANUAL_INSTANT_ELAPSED, + UNCHECKED_TIME_SUBTRACTION, +]); impl LateLintPass<'_> for UncheckedTimeSubtraction { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 352b8526b021..0a6b999775f4 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -100,7 +100,10 @@ impl TraitBounds { } } -impl_lint_pass!(TraitBounds => [TYPE_REPETITION_IN_BOUNDS, TRAIT_DUPLICATION_IN_BOUNDS]); +impl_lint_pass!(TraitBounds => [ + TRAIT_DUPLICATION_IN_BOUNDS, + TYPE_REPETITION_IN_BOUNDS, +]); impl<'tcx> LateLintPass<'tcx> for TraitBounds { fn check_generics(&mut self, cx: &LateContext<'tcx>, generics: &'tcx Generics<'_>) { diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 435cd7bcba4e..ad94dc92da1b 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -474,20 +474,20 @@ pub struct Transmute { } impl_lint_pass!(Transmute => [ CROSSPOINTER_TRANSMUTE, - TRANSMUTE_PTR_TO_REF, - TRANSMUTE_PTR_TO_PTR, - USELESS_TRANSMUTE, - WRONG_TRANSMUTE, + EAGER_TRANSMUTE, + MISSING_TRANSMUTE_ANNOTATIONS, + TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, TRANSMUTE_BYTES_TO_STR, TRANSMUTE_INT_TO_BOOL, TRANSMUTE_INT_TO_NON_ZERO, - UNSOUND_COLLECTION_TRANSMUTE, - TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, + TRANSMUTE_NULL_TO_FN, + TRANSMUTE_PTR_TO_PTR, + TRANSMUTE_PTR_TO_REF, TRANSMUTE_UNDEFINED_REPR, TRANSMUTING_NULL, - TRANSMUTE_NULL_TO_FN, - EAGER_TRANSMUTE, - MISSING_TRANSMUTE_ANNOTATIONS, + UNSOUND_COLLECTION_TRANSMUTE, + USELESS_TRANSMUTE, + WRONG_TRANSMUTE, ]); impl Transmute { pub fn new(conf: &'static Conf) -> Self { diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 7d97ce97f487..4ae2e6a9b1e3 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -398,16 +398,16 @@ pub struct Types { } impl_lint_pass!(Types => [ + BORROWED_BOX, BOX_COLLECTION, - VEC_BOX, - OPTION_OPTION, LINKEDLIST, - BORROWED_BOX, - REDUNDANT_ALLOCATION, + OPTION_OPTION, + OWNED_COW, RC_BUFFER, RC_MUTEX, + REDUNDANT_ALLOCATION, TYPE_COMPLEXITY, - OWNED_COW + VEC_BOX, ]); impl<'tcx> LateLintPass<'tcx> for Types { diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index 1b26b1b32b80..1ed78a53d640 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -106,7 +106,10 @@ impl UndocumentedUnsafeBlocks { } } -impl_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS, UNNECESSARY_SAFETY_COMMENT]); +impl_lint_pass!(UndocumentedUnsafeBlocks => [ + UNDOCUMENTED_UNSAFE_BLOCKS, + UNNECESSARY_SAFETY_COMMENT, +]); impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index 79571b0409d2..bef8b8fb4ee0 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -72,7 +72,11 @@ declare_clippy_lint! { "using a Unicode literal not in NFC normal form (see [Unicode tr15](http://www.unicode.org/reports/tr15/) for further information)" } -declare_lint_pass!(Unicode => [INVISIBLE_CHARACTERS, NON_ASCII_LITERAL, UNICODE_NOT_NFC]); +declare_lint_pass!(Unicode => [ + INVISIBLE_CHARACTERS, + NON_ASCII_LITERAL, + UNICODE_NOT_NFC, +]); impl LateLintPass<'_> for Unicode { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { diff --git a/clippy_lints/src/unit_types/mod.rs b/clippy_lints/src/unit_types/mod.rs index 4ffcc247acf6..13dd9d7b72c0 100644 --- a/clippy_lints/src/unit_types/mod.rs +++ b/clippy_lints/src/unit_types/mod.rs @@ -101,7 +101,7 @@ pub struct UnitTypes { format_args: FormatArgsStorage, } -impl_lint_pass!(UnitTypes => [LET_UNIT_VALUE, UNIT_CMP, UNIT_ARG]); +impl_lint_pass!(UnitTypes => [LET_UNIT_VALUE, UNIT_ARG, UNIT_CMP]); impl UnitTypes { pub fn new(format_args: FormatArgsStorage) -> Self { diff --git a/clippy_lints/src/unnecessary_map_on_constructor.rs b/clippy_lints/src/unnecessary_map_on_constructor.rs index fba530d0dfca..f221044584a5 100644 --- a/clippy_lints/src/unnecessary_map_on_constructor.rs +++ b/clippy_lints/src/unnecessary_map_on_constructor.rs @@ -31,7 +31,9 @@ declare_clippy_lint! { complexity, "using `map`/`map_err` on `Option` or `Result` constructors" } -declare_lint_pass!(UnnecessaryMapOnConstructor => [UNNECESSARY_MAP_ON_CONSTRUCTOR]); +declare_lint_pass!(UnnecessaryMapOnConstructor => [ + UNNECESSARY_MAP_ON_CONSTRUCTOR, +]); impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { diff --git a/clippy_lints/src/unnecessary_owned_empty_strings.rs b/clippy_lints/src/unnecessary_owned_empty_strings.rs index 0388450c9f7e..bcc10cbe7d7a 100644 --- a/clippy_lints/src/unnecessary_owned_empty_strings.rs +++ b/clippy_lints/src/unnecessary_owned_empty_strings.rs @@ -30,7 +30,9 @@ declare_clippy_lint! { style, "detects cases of references to owned empty strings being passed as an argument to a function expecting `&str`" } -declare_lint_pass!(UnnecessaryOwnedEmptyStrings => [UNNECESSARY_OWNED_EMPTY_STRINGS]); +declare_lint_pass!(UnnecessaryOwnedEmptyStrings => [ + UNNECESSARY_OWNED_EMPTY_STRINGS, +]); impl<'tcx> LateLintPass<'tcx> for UnnecessaryOwnedEmptyStrings { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index f26647fa3485..aafd1153f933 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -56,7 +56,7 @@ declare_clippy_lint! { "functions of type `Result<..>` or `Option`<...> that contain `expect()` or `unwrap()`" } -impl_lint_pass!(UnwrapInResult=> [UNWRAP_IN_RESULT]); +impl_lint_pass!(UnwrapInResult => [UNWRAP_IN_RESULT]); #[derive(Clone, Copy, Eq, PartialEq)] enum OptionOrResult { diff --git a/clippy_lints/src/visibility.rs b/clippy_lints/src/visibility.rs index d17b3df99216..429228912462 100644 --- a/clippy_lints/src/visibility.rs +++ b/clippy_lints/src/visibility.rs @@ -74,7 +74,11 @@ declare_clippy_lint! { restriction, "disallows usage of `pub(in )` with `in`" } -declare_lint_pass!(Visibility => [NEEDLESS_PUB_SELF, PUB_WITH_SHORTHAND, PUB_WITHOUT_SHORTHAND]); +declare_lint_pass!(Visibility => [ + NEEDLESS_PUB_SELF, + PUB_WITHOUT_SHORTHAND, + PUB_WITH_SHORTHAND, +]); impl EarlyLintPass for Visibility { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { diff --git a/clippy_lints/src/write/mod.rs b/clippy_lints/src/write/mod.rs index c42c047745bb..5f80adbab2bf 100644 --- a/clippy_lints/src/write/mod.rs +++ b/clippy_lints/src/write/mod.rs @@ -257,15 +257,15 @@ impl Write { } impl_lint_pass!(Write => [ - PRINT_WITH_NEWLINE, PRINTLN_EMPTY_STRING, - PRINT_STDOUT, + PRINT_LITERAL, PRINT_STDERR, + PRINT_STDOUT, + PRINT_WITH_NEWLINE, USE_DEBUG, - PRINT_LITERAL, - WRITE_WITH_NEWLINE, WRITELN_EMPTY_STRING, WRITE_LITERAL, + WRITE_WITH_NEWLINE, ]); impl<'tcx> LateLintPass<'tcx> for Write { From e16c8384396e481236cbc845ec570be18bf131d8 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 28 Oct 2025 08:47:38 -0400 Subject: [PATCH 03/14] `clippy_dev`: Sort all lint and lint pass declarations. --- clippy_dev/src/fmt.rs | 33 +- clippy_dev/src/generate.rs | 60 +- clippy_dev/src/parse.rs | 26 +- clippy_dev/src/utils.rs | 21 +- clippy_lints/src/absolute_paths.rs | 1 + clippy_lints/src/almost_complete_range.rs | 1 + clippy_lints/src/approx_const.rs | 4 +- clippy_lints/src/arc_with_non_send_sync.rs | 1 + clippy_lints/src/asm_syntax.rs | 56 +- clippy_lints/src/assertions_on_constants.rs | 1 + clippy_lints/src/assigning_clones.rs | 4 +- clippy_lints/src/attrs/mod.rs | 536 +- clippy_lints/src/await_holding_invalid.rs | 74 +- clippy_lints/src/bool_to_int_with_if.rs | 1 + clippy_lints/src/booleans.rs | 4 +- clippy_lints/src/byte_char_slices.rs | 1 + clippy_lints/src/cargo/mod.rs | 154 +- clippy_lints/src/casts/mod.rs | 916 +-- clippy_lints/src/checked_conversions.rs | 4 +- clippy_lints/src/cloned_ref_to_slice_refs.rs | 4 +- clippy_lints/src/coerce_container_to_any.rs | 1 + clippy_lints/src/cognitive_complexity.rs | 4 +- clippy_lints/src/collapsible_if.rs | 68 +- clippy_lints/src/collection_is_never_read.rs | 1 + clippy_lints/src/crate_in_macro_def.rs | 1 + clippy_lints/src/dbg_macro.rs | 4 +- clippy_lints/src/default.rs | 4 +- .../src/default_constructed_unit_structs.rs | 1 + .../src/default_instead_of_iter_empty.rs | 1 + .../src/default_union_representation.rs | 1 + clippy_lints/src/dereference.rs | 46 +- clippy_lints/src/derivable_impls.rs | 4 +- clippy_lints/src/derive/mod.rs | 124 +- clippy_lints/src/disallowed_fields.rs | 4 +- clippy_lints/src/disallowed_macros.rs | 4 +- clippy_lints/src/disallowed_methods.rs | 4 +- clippy_lints/src/disallowed_names.rs | 4 +- clippy_lints/src/disallowed_script_idents.rs | 4 +- clippy_lints/src/disallowed_types.rs | 4 +- clippy_lints/src/doc/mod.rs | 866 +-- clippy_lints/src/drop_forget_ref.rs | 4 +- clippy_lints/src/duplicate_mod.rs | 4 +- clippy_lints/src/empty_drop.rs | 1 + clippy_lints/src/empty_line_after.rs | 80 +- clippy_lints/src/empty_with_brackets.rs | 64 +- clippy_lints/src/endian_bytes.rs | 36 +- clippy_lints/src/error_impl_error.rs | 1 + clippy_lints/src/escape.rs | 4 +- clippy_lints/src/excessive_bools.rs | 84 +- clippy_lints/src/excessive_nesting.rs | 1 + clippy_lints/src/explicit_write.rs | 4 +- .../src/extra_unused_type_parameters.rs | 4 +- clippy_lints/src/float_literal.rs | 4 +- clippy_lints/src/format.rs | 4 +- clippy_lints/src/format_args.rs | 132 +- clippy_lints/src/format_impl.rs | 82 +- clippy_lints/src/format_push_string.rs | 1 + clippy_lints/src/formatting.rs | 120 +- clippy_lints/src/four_forward_slashes.rs | 1 + clippy_lints/src/from_over_into.rs | 4 +- clippy_lints/src/from_raw_with_void_ptr.rs | 1 + clippy_lints/src/functions/mod.rs | 506 +- clippy_lints/src/if_then_some_else_none.rs | 4 +- clippy_lints/src/ifs/mod.rs | 124 +- clippy_lints/src/ignored_unit_patterns.rs | 1 + clippy_lints/src/implicit_saturating_add.rs | 1 + clippy_lints/src/implicit_saturating_sub.rs | 8 +- clippy_lints/src/implied_bounds_in_impls.rs | 1 + clippy_lints/src/incompatible_msrv.rs | 4 +- .../src/inconsistent_struct_constructor.rs | 8 +- clippy_lints/src/index_refutable_slice.rs | 4 +- clippy_lints/src/indexing_slicing.rs | 60 +- clippy_lints/src/infallible_try_from.rs | 1 + clippy_lints/src/item_name_repetitions.rs | 75 +- clippy_lints/src/iter_without_into_iter.rs | 56 +- clippy_lints/src/large_const_arrays.rs | 4 +- clippy_lints/src/large_enum_variant.rs | 4 +- clippy_lints/src/large_futures.rs | 4 +- clippy_lints/src/large_include_file.rs | 4 +- clippy_lints/src/large_stack_arrays.rs | 4 +- clippy_lints/src/large_stack_frames.rs | 4 +- clippy_lints/src/legacy_numeric_constants.rs | 5 +- clippy_lints/src/len_zero.rs | 54 +- clippy_lints/src/let_underscore.rs | 64 +- clippy_lints/src/let_with_type_underscore.rs | 1 + clippy_lints/src/lifetimes.rs | 82 +- clippy_lints/src/literal_representation.rs | 122 +- clippy_lints/src/loops/mod.rs | 838 +-- clippy_lints/src/macro_metavars_in_unsafe.rs | 1 + clippy_lints/src/macro_use.rs | 4 +- clippy_lints/src/main_recursion.rs | 4 +- clippy_lints/src/manual_bits.rs | 4 +- clippy_lints/src/manual_checked_ops.rs | 1 + clippy_lints/src/manual_clamp.rs | 1 + clippy_lints/src/manual_float_methods.rs | 34 +- clippy_lints/src/manual_hash_one.rs | 4 +- clippy_lints/src/manual_ilog2.rs | 4 +- clippy_lints/src/manual_is_ascii_check.rs | 1 + clippy_lints/src/manual_is_power_of_two.rs | 4 +- clippy_lints/src/manual_main_separator_str.rs | 4 +- clippy_lints/src/manual_non_exhaustive.rs | 4 +- clippy_lints/src/manual_option_as_slice.rs | 4 +- clippy_lints/src/manual_range_patterns.rs | 1 + clippy_lints/src/manual_rem_euclid.rs | 4 +- clippy_lints/src/manual_retain.rs | 4 +- .../src/manual_slice_size_calculation.rs | 1 + clippy_lints/src/manual_string_new.rs | 1 + clippy_lints/src/manual_strip.rs | 4 +- clippy_lints/src/manual_take.rs | 5 +- clippy_lints/src/matches/mod.rs | 1102 ++-- clippy_lints/src/mem_replace.rs | 50 +- clippy_lints/src/methods/mod.rs | 5322 ++++++++--------- clippy_lints/src/min_ident_chars.rs | 1 + clippy_lints/src/misc.rs | 42 +- clippy_lints/src/misc_early/mod.rs | 278 +- .../src/mismatching_type_param_order.rs | 1 + .../src/missing_asserts_for_indexing.rs | 1 + .../src/missing_const_for_thread_local.rs | 4 +- clippy_lints/src/missing_doc.rs | 4 +- .../src/missing_enforced_import_rename.rs | 4 +- clippy_lints/src/missing_fields_in_debug.rs | 1 + clippy_lints/src/missing_inline.rs | 4 +- clippy_lints/src/missing_trait_methods.rs | 1 + .../src/mixed_read_write_in_expression.rs | 56 +- .../src/multiple_unsafe_ops_per_block.rs | 1 + clippy_lints/src/mut_key.rs | 4 +- clippy_lints/src/needless_bool.rs | 1 + .../src/needless_borrows_for_generic_args.rs | 8 +- clippy_lints/src/needless_else.rs | 1 + clippy_lints/src/needless_ifs.rs | 1 + clippy_lints/src/needless_late_init.rs | 1 + clippy_lints/src/needless_maybe_sized.rs | 1 + clippy_lints/src/needless_pass_by_ref_mut.rs | 4 +- clippy_lints/src/new_without_default.rs | 4 +- clippy_lints/src/no_effect.rs | 12 +- clippy_lints/src/no_mangle_with_rust_abi.rs | 1 + clippy_lints/src/non_canonical_impls.rs | 2 + clippy_lints/src/non_copy_const.rs | 86 +- clippy_lints/src/non_expressive_names.rs | 56 +- .../src/non_send_fields_in_send_ty.rs | 4 +- clippy_lints/src/non_std_lazy_statics.rs | 4 +- clippy_lints/src/nonstandard_macro_braces.rs | 4 +- clippy_lints/src/only_used_in_recursion.rs | 1 + clippy_lints/src/operators/mod.rs | 824 +-- clippy_lints/src/panic_unimplemented.rs | 30 +- clippy_lints/src/partial_pub_fields.rs | 1 + clippy_lints/src/partialeq_to_none.rs | 1 + clippy_lints/src/pass_by_ref_or_value.rs | 74 +- .../src/permissions_set_readonly_false.rs | 1 + clippy_lints/src/ptr/mod.rs | 72 +- clippy_lints/src/pub_underscore_fields.rs | 4 +- clippy_lints/src/pub_use.rs | 1 + clippy_lints/src/question_mark.rs | 4 +- clippy_lints/src/ranges.rs | 122 +- clippy_lints/src/raw_strings.rs | 42 +- clippy_lints/src/rc_clone_in_vec_init.rs | 1 + clippy_lints/src/read_zero_byte_vec.rs | 1 + clippy_lints/src/redundant_async_block.rs | 1 + clippy_lints/src/redundant_field_names.rs | 4 +- clippy_lints/src/redundant_locals.rs | 1 + clippy_lints/src/redundant_pub_crate.rs | 4 +- clippy_lints/src/redundant_slicing.rs | 48 +- .../src/redundant_static_lifetimes.rs | 4 +- .../src/redundant_type_annotations.rs | 1 + clippy_lints/src/ref_patterns.rs | 1 + clippy_lints/src/regex.rs | 64 +- clippy_lints/src/replace_box.rs | 4 +- .../src/reserve_after_initialization.rs | 1 + clippy_lints/src/same_length_and_capacity.rs | 1 + clippy_lints/src/semicolon_block.rs | 2 + clippy_lints/src/shadow.rs | 50 +- clippy_lints/src/single_call_fn.rs | 1 + .../src/single_component_path_imports.rs | 4 +- clippy_lints/src/single_range_in_vec_init.rs | 1 + clippy_lints/src/size_of_ref.rs | 1 + clippy_lints/src/std_instead_of_core.rs | 54 +- clippy_lints/src/string_patterns.rs | 10 +- clippy_lints/src/strings.rs | 177 +- clippy_lints/src/strlen_on_c_strings.rs | 4 +- .../src/suspicious_xor_used_as_pow.rs | 1 + clippy_lints/src/swap.rs | 52 +- clippy_lints/src/swap_ptr_to_ref.rs | 1 + clippy_lints/src/temporary_assignment.rs | 4 +- clippy_lints/src/time_subtraction.rs | 10 +- clippy_lints/src/trailing_empty_array.rs | 1 + clippy_lints/src/trait_bounds.rs | 56 +- clippy_lints/src/transmute/mod.rs | 404 +- clippy_lints/src/tuple_array_conversions.rs | 1 + clippy_lints/src/types/mod.rs | 308 +- clippy_lints/src/unconditional_recursion.rs | 4 +- .../src/undocumented_unsafe_blocks.rs | 11 +- clippy_lints/src/unit_types/mod.rs | 44 +- clippy_lints/src/unnecessary_box_returns.rs | 4 +- .../src/unnecessary_map_on_constructor.rs | 1 + .../src/unnecessary_owned_empty_strings.rs | 1 + clippy_lints/src/unnecessary_semicolon.rs | 4 +- .../src/unnecessary_struct_initialization.rs | 1 + clippy_lints/src/unnecessary_wraps.rs | 4 +- clippy_lints/src/unnested_or_patterns.rs | 4 +- clippy_lints/src/unused_async.rs | 4 +- clippy_lints/src/unused_result_ok.rs | 1 + clippy_lints/src/unused_rounding.rs | 1 + clippy_lints/src/unused_self.rs | 4 +- clippy_lints/src/unused_trait_names.rs | 4 +- clippy_lints/src/unwrap.rs | 56 +- clippy_lints/src/upper_case_acronyms.rs | 4 +- clippy_lints/src/use_self.rs | 4 +- clippy_lints/src/useless_conversion.rs | 4 +- clippy_lints/src/visibility.rs | 3 + clippy_lints/src/volatile_composites.rs | 1 + clippy_lints/src/wildcard_imports.rs | 4 +- clippy_lints/src/write/mod.rs | 170 +- clippy_lints/src/zombie_processes.rs | 1 + 213 files changed, 7932 insertions(+), 7753 deletions(-) diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index f4ee600dde04..d13f966b19c3 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -1,7 +1,9 @@ +use crate::generate::gen_sorted_lints_file; use crate::new_parse_cx; +use crate::parse::VecBuf; use crate::utils::{ - ErrAction, FileUpdater, UpdateMode, UpdateStatus, expect_action, run_with_output, slice_groups, - split_args_for_threads, walk_dir_no_dot_or_target, + ErrAction, FileUpdater, UpdateMode, UpdateStatus, expect_action, run_with_output, split_args_for_threads, + walk_dir_no_dot_or_target, }; use itertools::Itertools; use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize}; @@ -334,19 +336,24 @@ pub fn run(update_mode: UpdateMode) { } new_parse_cx(|cx| { - let data = cx.parse_lint_decls(); + let mut data = cx.parse_lint_decls(); + let (mut lints, passes) = data.split_by_lint_file(); let mut updater = FileUpdater::default(); + let mut ranges = VecBuf::with_capacity(256); - for passes in slice_groups(&data.lint_passes, |head, tail| { - tail.iter().take_while(|&x| x.path == head.path).count() - }) { - updater.update_file_checked("cargo dev fmt", update_mode, &passes[0].path, &mut |_, src, dst| { - let pos = passes.iter().fold(0u32, |start, pass| { - dst.push_str(&src[start as usize..pass.decl_range.start as usize]); - pass.gen_mac(dst); - pass.decl_range.end - }); - dst.push_str(&src[pos as usize..]); + for passes in passes { + let path = passes[0].path.clone(); + let mut lints = lints.remove(&*path); + let lints = lints.as_deref_mut().unwrap_or_default(); + updater.update_file_checked("cargo dev fmt", update_mode, &path, &mut |_, src, dst| { + gen_sorted_lints_file(src, dst, lints, passes, &mut ranges); + UpdateStatus::from_changed(src != dst) + }); + } + + for (&path, lints) in &mut lints { + updater.update_file_checked("cargo dev fmt", update_mode, path, &mut |_, src, dst| { + gen_sorted_lints_file(src, dst, lints, &mut [], &mut ranges); UpdateStatus::from_changed(src != dst) }); } diff --git a/clippy_dev/src/generate.rs b/clippy_dev/src/generate.rs index 0d86c0179cde..24e4218716ab 100644 --- a/clippy_dev/src/generate.rs +++ b/clippy_dev/src/generate.rs @@ -1,6 +1,7 @@ use crate::parse::cursor::Cursor; -use crate::parse::{Lint, LintData, LintPass}; +use crate::parse::{Lint, LintData, LintPass, VecBuf}; use crate::utils::{FileUpdater, UpdateMode, UpdateStatus, update_text_region_fn}; +use core::range::Range; use itertools::Itertools; use std::collections::HashSet; use std::fmt::Write; @@ -256,3 +257,60 @@ fn write_list<'a>( ListFmt::SingleLine } } + +/// Generates the contents of a lint's source file with all the lint and lint pass +/// declarations sorted. +pub fn gen_sorted_lints_file( + src: &str, + dst: &mut String, + lints: &mut [(&str, Range)], + passes: &mut [LintPass<'_>], + ranges: &mut VecBuf>, +) { + ranges.with(|ranges| { + ranges.extend(lints.iter().map(|&(_, x)| x)); + ranges.extend(passes.iter().map(|x| x.decl_range)); + ranges.sort_unstable_by_key(|x| x.start); + + lints.sort_unstable_by_key(|&(x, _)| x); + passes.sort_by_key(|x| x.name); + + let mut ranges = ranges.iter(); + let pos = if let Some(range) = ranges.next() { + dst.push_str(&src[..range.start as usize]); + for &(_, range) in &*lints { + dst.push_str(&src[range.start as usize..range.end as usize]); + dst.push_str("\n\n"); + } + for pass in passes { + pass.gen_mac(dst); + dst.push_str("\n\n"); + } + range.end + } else { + dst.push_str(src); + return; + }; + + let pos = ranges.fold(pos, |start, range| { + let s = &src[start as usize..range.start as usize]; + dst.push_str(if s.trim_start().is_empty() { + // Only whitespace between this and the previous item. No need to keep that. + "" + } else if src[..pos as usize].ends_with("\n\n") + && let Some(s) = s.strip_prefix("\n\n") + { + // Empty line before and after. Remove one of them. + s + } else { + // Remove only full lines unless something is in the way. + s.strip_prefix('\n').unwrap_or(s) + }); + range.end + }); + + // Since we always generate an empty line at the end, make sure to always skip it. + let s = &src[pos as usize..]; + dst.push_str(s.strip_prefix('\n').map_or(s, |s| s.strip_prefix('\n').unwrap_or(s))); + }); +} diff --git a/clippy_dev/src/parse.rs b/clippy_dev/src/parse.rs index 30eed05a4f8b..d51fb25552f9 100644 --- a/clippy_dev/src/parse.rs +++ b/clippy_dev/src/parse.rs @@ -1,7 +1,7 @@ pub mod cursor; use self::cursor::{Capture, Cursor}; -use crate::utils::{ErrAction, File, Scoped, expect_action, walk_dir_no_dot_or_target}; +use crate::utils::{ErrAction, File, Scoped, expect_action, slice_groups_mut, walk_dir_no_dot_or_target}; use core::fmt::{self, Display, Write as _}; use core::range::Range; use rustc_arena::DroplessArena; @@ -193,6 +193,30 @@ pub struct LintData<'cx> { pub lints: FxHashMap<&'cx str, Lint<'cx>>, pub lint_passes: Vec>, } +impl<'cx> LintData<'cx> { + #[expect(clippy::type_complexity)] + pub fn split_by_lint_file<'s>( + &'s mut self, + ) -> ( + FxHashMap<&'s Path, Vec<(&'s str, Range)>>, + impl Iterator]>, + ) { + #[expect(clippy::default_trait_access)] + let mut lints = FxHashMap::with_capacity_and_hasher(500, Default::default()); + for (&name, lint) in &self.lints { + if let Lint::Active(lint) = lint { + lints + .entry(&*lint.path) + .or_insert_with(|| Vec::with_capacity(8)) + .push((name, lint.declaration_range)); + } + } + let passes = slice_groups_mut(&mut self.lint_passes, |head, tail| { + tail.iter().take_while(|&x| x.path == head.path).count() + }); + (lints, passes) + } +} impl<'cx> ParseCxImpl<'cx> { /// Finds and parses all lint declarations. diff --git a/clippy_dev/src/utils.rs b/clippy_dev/src/utils.rs index 98a3458d6c2a..1f931140467e 100644 --- a/clippy_dev/src/utils.rs +++ b/clippy_dev/src/utils.rs @@ -1,5 +1,6 @@ use core::fmt::{self, Display}; use core::marker::PhantomData; +use core::mem; use core::num::NonZero; use core::ops::{Deref, DerefMut}; use core::range::Range; @@ -601,23 +602,25 @@ pub fn walk_dir_no_dot_or_target(p: impl AsRef) -> impl Iterator( - slice: &'a [T], - split_idx: impl FnMut(&'a T, &'a [T]) -> usize, -) -> impl Iterator { +pub fn slice_groups_mut( + slice: &mut [T], + split_idx: impl FnMut(&T, &[T]) -> usize, +) -> impl Iterator { struct I<'a, T, F> { - slice: &'a [T], + slice: &'a mut [T], split_idx: F, } - impl<'a, T, F: FnMut(&'a T, &'a [T]) -> usize> Iterator for I<'a, T, F> { - type Item = &'a [T]; + impl<'a, T, F: FnMut(&T, &[T]) -> usize> Iterator for I<'a, T, F> { + type Item = &'a mut [T]; fn next(&mut self) -> Option { let (head, tail) = self.slice.split_first()?; - if let Some((head, tail)) = self.slice.split_at_checked((self.split_idx)(head, tail) + 1) { + let idx = (self.split_idx)(head, tail) + 1; + // `mem::take` makes it so `self.slice` isn't reborrowed. + if let Some((head, tail)) = mem::take(&mut self.slice).split_at_mut_checked(idx) { self.slice = tail; Some(head) } else { - self.slice = &[]; + self.slice = &mut []; None } } diff --git a/clippy_lints/src/absolute_paths.rs b/clippy_lints/src/absolute_paths.rs index 1af6d448a93c..fd515939dfb8 100644 --- a/clippy_lints/src/absolute_paths.rs +++ b/clippy_lints/src/absolute_paths.rs @@ -52,6 +52,7 @@ declare_clippy_lint! { restriction, "checks for usage of an item without a `use` statement" } + impl_lint_pass!(AbsolutePaths => [ABSOLUTE_PATHS]); pub struct AbsolutePaths { diff --git a/clippy_lints/src/almost_complete_range.rs b/clippy_lints/src/almost_complete_range.rs index 4f55968d5625..258970393023 100644 --- a/clippy_lints/src/almost_complete_range.rs +++ b/clippy_lints/src/almost_complete_range.rs @@ -28,6 +28,7 @@ declare_clippy_lint! { suspicious, "almost complete range" } + impl_lint_pass!(AlmostCompleteRange => [ALMOST_COMPLETE_RANGE]); pub struct AlmostCompleteRange { diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs index a3710ca51655..2ea921e5d461 100644 --- a/clippy_lints/src/approx_const.rs +++ b/clippy_lints/src/approx_const.rs @@ -39,6 +39,8 @@ declare_clippy_lint! { "the approximate of a known float constant (in `std::fXX::consts`)" } +impl_lint_pass!(ApproxConstant => [APPROX_CONSTANT]); + // Tuples are of the form (constant, name, min_digits, msrv) const KNOWN_CONSTS: [(f64, &str, usize, Option); 19] = [ (f64::E, "E", 4, None), @@ -111,8 +113,6 @@ impl ApproxConstant { } } -impl_lint_pass!(ApproxConstant => [APPROX_CONSTANT]); - fn count_digits_after_dot(input: &str) -> usize { input .char_indices() diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs index acfdfa65baed..e449b06199d3 100644 --- a/clippy_lints/src/arc_with_non_send_sync.rs +++ b/clippy_lints/src/arc_with_non_send_sync.rs @@ -39,6 +39,7 @@ declare_clippy_lint! { suspicious, "using `Arc` with a type that does not implement `Send` and `Sync`" } + declare_lint_pass!(ArcWithNonSendSync => [ARC_WITH_NON_SEND_SYNC]); impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync { diff --git a/clippy_lints/src/asm_syntax.rs b/clippy_lints/src/asm_syntax.rs index 69a8eb7d94e7..3c5cf74d5a17 100644 --- a/clippy_lints/src/asm_syntax.rs +++ b/clippy_lints/src/asm_syntax.rs @@ -59,10 +59,10 @@ fn check_asm_syntax( declare_clippy_lint! { /// ### What it does - /// Checks for usage of Intel x86 assembly syntax. + /// Checks for usage of AT&T x86 assembly syntax. /// /// ### Why restrict this? - /// To enforce consistent use of AT&T x86 assembly syntax. + /// To enforce consistent use of Intel x86 assembly syntax. /// /// ### Example /// @@ -71,7 +71,7 @@ declare_clippy_lint! { /// # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] /// # unsafe { let ptr = "".as_ptr(); /// # use std::arch::asm; - /// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr); + /// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax)); /// # } /// ``` /// Use instead: @@ -80,37 +80,21 @@ declare_clippy_lint! { /// # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] /// # unsafe { let ptr = "".as_ptr(); /// # use std::arch::asm; - /// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax)); + /// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr); /// # } /// ``` #[clippy::version = "1.49.0"] - pub INLINE_ASM_X86_INTEL_SYNTAX, + pub INLINE_ASM_X86_ATT_SYNTAX, restriction, - "prefer AT&T x86 assembly syntax" -} - -declare_lint_pass!(InlineAsmX86IntelSyntax => [INLINE_ASM_X86_INTEL_SYNTAX]); - -impl EarlyLintPass for InlineAsmX86IntelSyntax { - fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if let ExprKind::InlineAsm(inline_asm) = &expr.kind { - check_asm_syntax(INLINE_ASM_X86_INTEL_SYNTAX, cx, inline_asm, expr.span, AsmStyle::Intel); - } - } - - fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if let ItemKind::GlobalAsm(inline_asm) = &item.kind { - check_asm_syntax(INLINE_ASM_X86_INTEL_SYNTAX, cx, inline_asm, item.span, AsmStyle::Intel); - } - } + "prefer Intel x86 assembly syntax" } declare_clippy_lint! { /// ### What it does - /// Checks for usage of AT&T x86 assembly syntax. + /// Checks for usage of Intel x86 assembly syntax. /// /// ### Why restrict this? - /// To enforce consistent use of Intel x86 assembly syntax. + /// To enforce consistent use of AT&T x86 assembly syntax. /// /// ### Example /// @@ -119,7 +103,7 @@ declare_clippy_lint! { /// # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] /// # unsafe { let ptr = "".as_ptr(); /// # use std::arch::asm; - /// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax)); + /// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr); /// # } /// ``` /// Use instead: @@ -128,17 +112,33 @@ declare_clippy_lint! { /// # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] /// # unsafe { let ptr = "".as_ptr(); /// # use std::arch::asm; - /// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr); + /// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax)); /// # } /// ``` #[clippy::version = "1.49.0"] - pub INLINE_ASM_X86_ATT_SYNTAX, + pub INLINE_ASM_X86_INTEL_SYNTAX, restriction, - "prefer Intel x86 assembly syntax" + "prefer AT&T x86 assembly syntax" } declare_lint_pass!(InlineAsmX86AttSyntax => [INLINE_ASM_X86_ATT_SYNTAX]); +declare_lint_pass!(InlineAsmX86IntelSyntax => [INLINE_ASM_X86_INTEL_SYNTAX]); + +impl EarlyLintPass for InlineAsmX86IntelSyntax { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if let ExprKind::InlineAsm(inline_asm) = &expr.kind { + check_asm_syntax(INLINE_ASM_X86_INTEL_SYNTAX, cx, inline_asm, expr.span, AsmStyle::Intel); + } + } + + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + if let ItemKind::GlobalAsm(inline_asm) = &item.kind { + check_asm_syntax(INLINE_ASM_X86_INTEL_SYNTAX, cx, inline_asm, item.span, AsmStyle::Intel); + } + } +} + impl EarlyLintPass for InlineAsmX86AttSyntax { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::InlineAsm(inline_asm) = &expr.kind { diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 4aa55e53445c..6e57d0608bed 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -33,6 +33,7 @@ declare_clippy_lint! { } impl_lint_pass!(AssertionsOnConstants => [ASSERTIONS_ON_CONSTANTS]); + pub struct AssertionsOnConstants { msrv: Msrv, } diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index efce23d13a38..60bc9b2b5b85 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -53,6 +53,8 @@ declare_clippy_lint! { "assigning the result of cloning may be inefficient" } +impl_lint_pass!(AssigningClones => [ASSIGNING_CLONES]); + pub struct AssigningClones { msrv: Msrv, } @@ -63,8 +65,6 @@ impl AssigningClones { } } -impl_lint_pass!(AssigningClones => [ASSIGNING_CLONES]); - impl<'tcx> LateLintPass<'tcx> for AssigningClones { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { if let ExprKind::Assign(lhs, rhs, _) = e.kind diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs index 694b6625ffaf..c15a378053e3 100644 --- a/clippy_lints/src/attrs/mod.rs +++ b/clippy_lints/src/attrs/mod.rs @@ -25,106 +25,60 @@ use utils::{is_lint_level, is_relevant_impl, is_relevant_item, is_relevant_trait declare_clippy_lint! { /// ### What it does - /// Checks for items annotated with `#[inline(always)]`, - /// unless the annotated function is empty or simply panics. - /// - /// ### Why is this bad? - /// While there are valid uses of this annotation (and once - /// you know when to use it, by all means `allow` this lint), it's a common - /// newbie-mistake to pepper one's code with it. - /// - /// As a rule of thumb, before slapping `#[inline(always)]` on a function, - /// measure if that additional function call really affects your runtime profile - /// sufficiently to make up for the increase in compile time. - /// - /// ### Known problems - /// False positives, big time. This lint is meant to be - /// deactivated by everyone doing serious performance work. This means having - /// done the measurement. - /// - /// ### Example - /// ```ignore - /// #[inline(always)] - /// fn not_quite_hot_code(..) { ... } - /// ``` - #[clippy::version = "pre 1.29.0"] - pub INLINE_ALWAYS, - pedantic, - "use of `#[inline(always)]`" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for `extern crate` and `use` items annotated with - /// lint attributes. - /// - /// This lint permits lint attributes for lints emitted on the items themself. - /// For `use` items these lints are: - /// * ambiguous_glob_reexports - /// * dead_code - /// * deprecated - /// * hidden_glob_reexports - /// * unreachable_pub - /// * unused - /// * unused_braces - /// * unused_import_braces - /// * clippy::disallowed_types - /// * clippy::enum_glob_use - /// * clippy::macro_use_imports - /// * clippy::module_name_repetitions - /// * clippy::redundant_pub_crate - /// * clippy::single_component_path_imports - /// * clippy::unsafe_removed_from_name - /// * clippy::wildcard_imports + /// Checks for usage of the `#[allow]` attribute and suggests replacing it with + /// the `#[expect]` attribute (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html)) /// - /// For `extern crate` items these lints are: - /// * `unused_imports` on items with `#[macro_use]` + /// This lint only warns outer attributes (`#[allow]`), as inner attributes + /// (`#![allow]`) are usually used to enable or disable lints on a global scale. /// /// ### Why is this bad? - /// Lint attributes have no effect on crate imports. Most - /// likely a `!` was forgotten. + /// `#[expect]` attributes suppress the lint emission, but emit a warning, if + /// the expectation is unfulfilled. This can be useful to be notified when the + /// lint is no longer triggered. /// /// ### Example - /// ```ignore - /// #[deny(dead_code)] - /// extern crate foo; - /// #[forbid(dead_code)] - /// use foo::bar; + /// ```rust,ignore + /// #[allow(unused_mut)] + /// fn foo() -> usize { + /// let mut a = Vec::new(); + /// a.len() + /// } /// ``` - /// /// Use instead: /// ```rust,ignore - /// #[allow(unused_imports)] - /// use foo::baz; - /// #[allow(unused_imports)] - /// #[macro_use] - /// extern crate baz; + /// #[expect(unused_mut)] + /// fn foo() -> usize { + /// let mut a = Vec::new(); + /// a.len() + /// } /// ``` - #[clippy::version = "pre 1.29.0"] - pub USELESS_ATTRIBUTE, - correctness, - "use of lint attributes on `extern crate` items" + #[clippy::version = "1.70.0"] + pub ALLOW_ATTRIBUTES, + restriction, + "`#[allow]` will not trigger if a warning isn't found. `#[expect]` triggers if there are no warnings." } declare_clippy_lint! { /// ### What it does - /// Checks for `#[deprecated]` annotations with a `since` - /// field that is not a valid semantic version. Also allows "TBD" to signal - /// future deprecation. + /// Checks for attributes that allow lints without a reason. /// - /// ### Why is this bad? - /// For checking the version of the deprecation, it must be - /// a valid semver. Failing that, the contained information is useless. + /// ### Why restrict this? + /// Justifying each `allow` helps readers understand the reasoning, + /// and may allow removing `allow` attributes if their purpose is obsolete. /// /// ### Example /// ```no_run - /// #[deprecated(since = "forever")] - /// fn something_else() { /* ... */ } + /// #![allow(clippy::some_lint)] /// ``` - #[clippy::version = "pre 1.29.0"] - pub DEPRECATED_SEMVER, - correctness, - "use of `#[deprecated(since = \"x\")]` where x is not semver" + /// + /// Use instead: + /// ```no_run + /// #![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")] + /// ``` + #[clippy::version = "1.61.0"] + pub ALLOW_ATTRIBUTES_WITHOUT_REASON, + restriction, + "ensures that all `allow` and `expect` attributes have a reason" } declare_clippy_lint! { @@ -183,95 +137,195 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for attributes that allow lints without a reason. + /// Checks for `#[cfg_attr(feature = "cargo-clippy", ...)]` and for + /// `#[cfg(feature = "cargo-clippy")]` and suggests to replace it with + /// `#[cfg_attr(clippy, ...)]` or `#[cfg(clippy)]`. /// - /// ### Why restrict this? - /// Justifying each `allow` helps readers understand the reasoning, - /// and may allow removing `allow` attributes if their purpose is obsolete. + /// ### Why is this bad? + /// This feature has been deprecated for years and shouldn't be used anymore. /// /// ### Example /// ```no_run - /// #![allow(clippy::some_lint)] + /// #[cfg(feature = "cargo-clippy")] + /// struct Bar; /// ``` /// /// Use instead: /// ```no_run - /// #![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")] + /// #[cfg(clippy)] + /// struct Bar; /// ``` - #[clippy::version = "1.61.0"] - pub ALLOW_ATTRIBUTES_WITHOUT_REASON, - restriction, - "ensures that all `allow` and `expect` attributes have a reason" + #[clippy::version = "1.78.0"] + pub DEPRECATED_CLIPPY_CFG_ATTR, + suspicious, + "usage of `cfg(feature = \"cargo-clippy\")` instead of `cfg(clippy)`" } declare_clippy_lint! { /// ### What it does - /// Checks for usage of the `#[allow]` attribute and suggests replacing it with - /// the `#[expect]` attribute (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html)) + /// Checks for `#[deprecated]` annotations with a `since` + /// field that is not a valid semantic version. Also allows "TBD" to signal + /// future deprecation. /// - /// This lint only warns outer attributes (`#[allow]`), as inner attributes - /// (`#![allow]`) are usually used to enable or disable lints on a global scale. + /// ### Why is this bad? + /// For checking the version of the deprecation, it must be + /// a valid semver. Failing that, the contained information is useless. + /// + /// ### Example + /// ```no_run + /// #[deprecated(since = "forever")] + /// fn something_else() { /* ... */ } + /// ``` + #[clippy::version = "pre 1.29.0"] + pub DEPRECATED_SEMVER, + correctness, + "use of `#[deprecated(since = \"x\")]` where x is not semver" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for attributes that appear two or more times. /// /// ### Why is this bad? - /// `#[expect]` attributes suppress the lint emission, but emit a warning, if - /// the expectation is unfulfilled. This can be useful to be notified when the - /// lint is no longer triggered. + /// Repeating an attribute on the same item (or globally on the same crate) + /// is unnecessary and doesn't have an effect. /// /// ### Example - /// ```rust,ignore - /// #[allow(unused_mut)] - /// fn foo() -> usize { - /// let mut a = Vec::new(); - /// a.len() - /// } + /// ```no_run + /// #[allow(dead_code)] + /// #[allow(dead_code)] + /// fn foo() {} /// ``` + /// /// Use instead: - /// ```rust,ignore - /// #[expect(unused_mut)] - /// fn foo() -> usize { - /// let mut a = Vec::new(); - /// a.len() + /// ```no_run + /// #[allow(dead_code)] + /// fn foo() {} + /// ``` + #[clippy::version = "1.79.0"] + pub DUPLICATED_ATTRIBUTES, + suspicious, + "duplicated attribute" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for ignored tests without messages. + /// + /// ### Why is this bad? + /// The reason for ignoring the test may not be obvious. + /// + /// ### Example + /// ```no_run + /// #[test] + /// #[ignore] + /// fn test() {} + /// ``` + /// Use instead: + /// ```no_run + /// #[test] + /// #[ignore = "Some good reason"] + /// fn test() {} + /// ``` + /// + /// ### Note + /// Clippy can only lint compiled code. For this lint to trigger, you must configure `cargo clippy` + /// to include test compilation, for instance, by using flags such as `--tests` or `--all-targets`. + #[clippy::version = "1.88.0"] + pub IGNORE_WITHOUT_REASON, + pedantic, + "ignored tests without messages" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for items annotated with `#[inline(always)]`, + /// unless the annotated function is empty or simply panics. + /// + /// ### Why is this bad? + /// While there are valid uses of this annotation (and once + /// you know when to use it, by all means `allow` this lint), it's a common + /// newbie-mistake to pepper one's code with it. + /// + /// As a rule of thumb, before slapping `#[inline(always)]` on a function, + /// measure if that additional function call really affects your runtime profile + /// sufficiently to make up for the increase in compile time. + /// + /// ### Known problems + /// False positives, big time. This lint is meant to be + /// deactivated by everyone doing serious performance work. This means having + /// done the measurement. + /// + /// ### Example + /// ```ignore + /// #[inline(always)] + /// fn not_quite_hot_code(..) { ... } + /// ``` + #[clippy::version = "pre 1.29.0"] + pub INLINE_ALWAYS, + pedantic, + "use of `#[inline(always)]`" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for items that have the same kind of attributes with mixed styles (inner/outer). + /// + /// ### Why is this bad? + /// Having both style of said attributes makes it more complicated to read code. + /// + /// ### Known problems + /// This lint currently has false-negatives when mixing same attributes + /// but they have different path symbols, for example: + /// ```ignore + /// #[custom_attribute] + /// pub fn foo() { + /// #![my_crate::custom_attribute] + /// } + /// ``` + /// + /// ### Example + /// ```no_run + /// #[cfg(linux)] + /// pub fn foo() { + /// #![cfg(windows)] + /// } + /// ``` + /// Use instead: + /// ```no_run + /// #[cfg(linux)] + /// #[cfg(windows)] + /// pub fn foo() { /// } /// ``` - #[clippy::version = "1.70.0"] - pub ALLOW_ATTRIBUTES, - restriction, - "`#[allow]` will not trigger if a warning isn't found. `#[expect]` triggers if there are no warnings." + #[clippy::version = "1.78.0"] + pub MIXED_ATTRIBUTES_STYLE, + style, + "item has both inner and outer attributes" } declare_clippy_lint! { /// ### What it does - /// Checks for `#[should_panic]` attributes without specifying the expected panic message. + /// Checks for `any` and `all` combinators in `cfg` with only one condition. /// /// ### Why is this bad? - /// The expected panic message should be specified to ensure that the test is actually - /// panicking with the expected message, and not another unrelated panic. + /// If there is only one condition, no need to wrap it into `any` or `all` combinators. /// /// ### Example /// ```no_run - /// fn random() -> i32 { 0 } - /// - /// #[should_panic] - /// #[test] - /// fn my_test() { - /// let _ = 1 / random(); - /// } + /// #[cfg(any(unix))] + /// pub struct Bar; /// ``` /// /// Use instead: /// ```no_run - /// fn random() -> i32 { 0 } - /// - /// #[should_panic = "attempt to divide by zero"] - /// #[test] - /// fn my_test() { - /// let _ = 1 / random(); - /// } + /// #[cfg(unix)] + /// pub struct Bar; /// ``` - #[clippy::version = "1.74.0"] - pub SHOULD_PANIC_WITHOUT_EXPECT, - pedantic, - "ensures that all `should_panic` attributes specify its expected panic message" + #[clippy::version = "1.71.0"] + pub NON_MINIMAL_CFG, + style, + "ensure that all `cfg(any())` and `cfg(all())` have more than one condition" } declare_clippy_lint! { @@ -314,52 +368,37 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for `any` and `all` combinators in `cfg` with only one condition. + /// Checks for `#[should_panic]` attributes without specifying the expected panic message. /// /// ### Why is this bad? - /// If there is only one condition, no need to wrap it into `any` or `all` combinators. + /// The expected panic message should be specified to ensure that the test is actually + /// panicking with the expected message, and not another unrelated panic. /// /// ### Example /// ```no_run - /// #[cfg(any(unix))] - /// pub struct Bar; - /// ``` - /// - /// Use instead: - /// ```no_run - /// #[cfg(unix)] - /// pub struct Bar; - /// ``` - #[clippy::version = "1.71.0"] - pub NON_MINIMAL_CFG, - style, - "ensure that all `cfg(any())` and `cfg(all())` have more than one condition" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for `#[cfg_attr(feature = "cargo-clippy", ...)]` and for - /// `#[cfg(feature = "cargo-clippy")]` and suggests to replace it with - /// `#[cfg_attr(clippy, ...)]` or `#[cfg(clippy)]`. - /// - /// ### Why is this bad? - /// This feature has been deprecated for years and shouldn't be used anymore. + /// fn random() -> i32 { 0 } /// - /// ### Example - /// ```no_run - /// #[cfg(feature = "cargo-clippy")] - /// struct Bar; + /// #[should_panic] + /// #[test] + /// fn my_test() { + /// let _ = 1 / random(); + /// } /// ``` /// /// Use instead: /// ```no_run - /// #[cfg(clippy)] - /// struct Bar; + /// fn random() -> i32 { 0 } + /// + /// #[should_panic = "attempt to divide by zero"] + /// #[test] + /// fn my_test() { + /// let _ = 1 / random(); + /// } /// ``` - #[clippy::version = "1.78.0"] - pub DEPRECATED_CLIPPY_CFG_ATTR, - suspicious, - "usage of `cfg(feature = \"cargo-clippy\")` instead of `cfg(clippy)`" + #[clippy::version = "1.74.0"] + pub SHOULD_PANIC_WITHOUT_EXPECT, + pedantic, + "ensures that all `should_panic` attributes specify its expected panic message" } declare_clippy_lint! { @@ -388,102 +427,82 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for items that have the same kind of attributes with mixed styles (inner/outer). - /// - /// ### Why is this bad? - /// Having both style of said attributes makes it more complicated to read code. + /// Checks for `extern crate` and `use` items annotated with + /// lint attributes. /// - /// ### Known problems - /// This lint currently has false-negatives when mixing same attributes - /// but they have different path symbols, for example: - /// ```ignore - /// #[custom_attribute] - /// pub fn foo() { - /// #![my_crate::custom_attribute] - /// } - /// ``` + /// This lint permits lint attributes for lints emitted on the items themself. + /// For `use` items these lints are: + /// * ambiguous_glob_reexports + /// * dead_code + /// * deprecated + /// * hidden_glob_reexports + /// * unreachable_pub + /// * unused + /// * unused_braces + /// * unused_import_braces + /// * clippy::disallowed_types + /// * clippy::enum_glob_use + /// * clippy::macro_use_imports + /// * clippy::module_name_repetitions + /// * clippy::redundant_pub_crate + /// * clippy::single_component_path_imports + /// * clippy::unsafe_removed_from_name + /// * clippy::wildcard_imports /// - /// ### Example - /// ```no_run - /// #[cfg(linux)] - /// pub fn foo() { - /// #![cfg(windows)] - /// } - /// ``` - /// Use instead: - /// ```no_run - /// #[cfg(linux)] - /// #[cfg(windows)] - /// pub fn foo() { - /// } - /// ``` - #[clippy::version = "1.78.0"] - pub MIXED_ATTRIBUTES_STYLE, - style, - "item has both inner and outer attributes" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for attributes that appear two or more times. + /// For `extern crate` items these lints are: + /// * `unused_imports` on items with `#[macro_use]` /// /// ### Why is this bad? - /// Repeating an attribute on the same item (or globally on the same crate) - /// is unnecessary and doesn't have an effect. + /// Lint attributes have no effect on crate imports. Most + /// likely a `!` was forgotten. /// /// ### Example - /// ```no_run - /// #[allow(dead_code)] - /// #[allow(dead_code)] - /// fn foo() {} + /// ```ignore + /// #[deny(dead_code)] + /// extern crate foo; + /// #[forbid(dead_code)] + /// use foo::bar; /// ``` /// /// Use instead: - /// ```no_run - /// #[allow(dead_code)] - /// fn foo() {} + /// ```rust,ignore + /// #[allow(unused_imports)] + /// use foo::baz; + /// #[allow(unused_imports)] + /// #[macro_use] + /// extern crate baz; /// ``` - #[clippy::version = "1.79.0"] - pub DUPLICATED_ATTRIBUTES, - suspicious, - "duplicated attribute" + #[clippy::version = "pre 1.29.0"] + pub USELESS_ATTRIBUTE, + correctness, + "use of lint attributes on `extern crate` items" } -declare_clippy_lint! { - /// ### What it does - /// Checks for ignored tests without messages. - /// - /// ### Why is this bad? - /// The reason for ignoring the test may not be obvious. - /// - /// ### Example - /// ```no_run - /// #[test] - /// #[ignore] - /// fn test() {} - /// ``` - /// Use instead: - /// ```no_run - /// #[test] - /// #[ignore = "Some good reason"] - /// fn test() {} - /// ``` - /// - /// ### Note - /// Clippy can only lint compiled code. For this lint to trigger, you must configure `cargo clippy` - /// to include test compilation, for instance, by using flags such as `--tests` or `--all-targets`. - #[clippy::version = "1.88.0"] - pub IGNORE_WITHOUT_REASON, - pedantic, - "ignored tests without messages" -} +impl_lint_pass!(Attributes => [INLINE_ALWAYS, REPR_PACKED_WITHOUT_ABI]); + +impl_lint_pass!(EarlyAttributes => [ + DEPRECATED_CFG_ATTR, + DEPRECATED_CLIPPY_CFG_ATTR, + NON_MINIMAL_CFG, + UNNECESSARY_CLIPPY_CFG, +]); + +impl_lint_pass!(PostExpansionEarlyAttributes => [ + ALLOW_ATTRIBUTES, + ALLOW_ATTRIBUTES_WITHOUT_REASON, + BLANKET_CLIPPY_RESTRICTION_LINTS, + DEPRECATED_SEMVER, + DUPLICATED_ATTRIBUTES, + IGNORE_WITHOUT_REASON, + MIXED_ATTRIBUTES_STYLE, + SHOULD_PANIC_WITHOUT_EXPECT, + USELESS_ATTRIBUTE, +]); pub struct Attributes { msrv: Msrv, } -impl_lint_pass!(Attributes => [INLINE_ALWAYS, REPR_PACKED_WITHOUT_ABI]); - impl Attributes { pub fn new(conf: &'static Conf) -> Self { Self { msrv: conf.msrv } @@ -526,13 +545,6 @@ impl EarlyAttributes { } } -impl_lint_pass!(EarlyAttributes => [ - DEPRECATED_CFG_ATTR, - DEPRECATED_CLIPPY_CFG_ATTR, - NON_MINIMAL_CFG, - UNNECESSARY_CLIPPY_CFG, -]); - impl EarlyLintPass for EarlyAttributes { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { deprecated_cfg_attr::check(cx, attr, &self.msrv); @@ -555,18 +567,6 @@ impl PostExpansionEarlyAttributes { } } -impl_lint_pass!(PostExpansionEarlyAttributes => [ - ALLOW_ATTRIBUTES, - ALLOW_ATTRIBUTES_WITHOUT_REASON, - BLANKET_CLIPPY_RESTRICTION_LINTS, - DEPRECATED_SEMVER, - DUPLICATED_ATTRIBUTES, - IGNORE_WITHOUT_REASON, - MIXED_ATTRIBUTES_STYLE, - SHOULD_PANIC_WITHOUT_EXPECT, - USELESS_ATTRIBUTE, -]); - impl EarlyLintPass for PostExpansionEarlyAttributes { fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) { blanket_clippy_restriction_lints::check_command_line(cx); diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 2d61c5e0b78a..dbd7dbdd1c6f 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -10,6 +10,43 @@ use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; use rustc_span::{Span, sym}; +declare_clippy_lint! { + /// ### What it does + /// Allows users to configure types which should not be held across await + /// suspension points. + /// + /// ### Why is this bad? + /// There are some types which are perfectly safe to use concurrently from + /// a memory access perspective, but that will cause bugs at runtime if + /// they are held in such a way. + /// + /// ### Example + /// + /// ```toml + /// await-holding-invalid-types = [ + /// # You can specify a type name + /// "CustomLockType", + /// # You can (optionally) specify a reason + /// { path = "OtherCustomLockType", reason = "Relies on a thread local" } + /// ] + /// ``` + /// + /// ```no_run + /// # async fn baz() {} + /// struct CustomLockType; + /// struct OtherCustomLockType; + /// async fn foo() { + /// let _x = CustomLockType; + /// let _y = OtherCustomLockType; + /// baz().await; // Lint violation + /// } + /// ``` + #[clippy::version = "1.62.0"] + pub AWAIT_HOLDING_INVALID_TYPE, + suspicious, + "holding a type across an await point which is not allowed to be held as per the configuration" +} + declare_clippy_lint! { /// ### What it does /// Checks for calls to `await` while holding a non-async-aware @@ -134,43 +171,6 @@ declare_clippy_lint! { "inside an async function, holding a `RefCell` ref while calling `await`" } -declare_clippy_lint! { - /// ### What it does - /// Allows users to configure types which should not be held across await - /// suspension points. - /// - /// ### Why is this bad? - /// There are some types which are perfectly safe to use concurrently from - /// a memory access perspective, but that will cause bugs at runtime if - /// they are held in such a way. - /// - /// ### Example - /// - /// ```toml - /// await-holding-invalid-types = [ - /// # You can specify a type name - /// "CustomLockType", - /// # You can (optionally) specify a reason - /// { path = "OtherCustomLockType", reason = "Relies on a thread local" } - /// ] - /// ``` - /// - /// ```no_run - /// # async fn baz() {} - /// struct CustomLockType; - /// struct OtherCustomLockType; - /// async fn foo() { - /// let _x = CustomLockType; - /// let _y = OtherCustomLockType; - /// baz().await; // Lint violation - /// } - /// ``` - #[clippy::version = "1.62.0"] - pub AWAIT_HOLDING_INVALID_TYPE, - suspicious, - "holding a type across an await point which is not allowed to be held as per the configuration" -} - impl_lint_pass!(AwaitHolding => [ AWAIT_HOLDING_INVALID_TYPE, AWAIT_HOLDING_LOCK, diff --git a/clippy_lints/src/bool_to_int_with_if.rs b/clippy_lints/src/bool_to_int_with_if.rs index 129e77478406..b98a20a90ccb 100644 --- a/clippy_lints/src/bool_to_int_with_if.rs +++ b/clippy_lints/src/bool_to_int_with_if.rs @@ -43,6 +43,7 @@ declare_clippy_lint! { pedantic, "using if to convert bool to int" } + declare_lint_pass!(BoolToIntWithIf => [BOOL_TO_INT_WITH_IF]); impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf { diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 0bd459d8b021..8b7619d11a83 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -74,6 +74,8 @@ declare_clippy_lint! { "boolean expressions that contain terminals which can be eliminated" } +impl_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, OVERLY_COMPLEX_BOOL_EXPR]); + // For each pairs, both orders are considered. const METHODS_WITH_NEGATION: [(Option, Symbol, Symbol); 3] = [ (None, sym::is_some, sym::is_none), @@ -91,8 +93,6 @@ impl NonminimalBool { } } -impl_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, OVERLY_COMPLEX_BOOL_EXPR]); - impl<'tcx> LateLintPass<'tcx> for NonminimalBool { fn check_fn( &mut self, diff --git a/clippy_lints/src/byte_char_slices.rs b/clippy_lints/src/byte_char_slices.rs index fc9931439e93..6c023189f69e 100644 --- a/clippy_lints/src/byte_char_slices.rs +++ b/clippy_lints/src/byte_char_slices.rs @@ -27,6 +27,7 @@ declare_clippy_lint! { style, "hard to read byte char slice" } + declare_lint_pass!(ByteCharSlice => [BYTE_CHAR_SLICES]); impl EarlyLintPass for ByteCharSlice { diff --git a/clippy_lints/src/cargo/mod.rs b/clippy_lints/src/cargo/mod.rs index 2fb468aed618..0aa6e4c3e8e2 100644 --- a/clippy_lints/src/cargo/mod.rs +++ b/clippy_lints/src/cargo/mod.rs @@ -58,34 +58,68 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for feature names with prefix `use-`, `with-` or suffix `-support` + /// Checks for lint groups with the same priority as lints in the `Cargo.toml` + /// [`[lints]` table](https://doc.rust-lang.org/cargo/reference/manifest.html#the-lints-section). + /// + /// This lint will be removed once [cargo#12918](https://github.com/rust-lang/cargo/issues/12918) + /// is resolved. /// /// ### Why is this bad? - /// These prefixes and suffixes have no significant meaning. + /// The order of lints in the `[lints]` is ignored, to have a lint override a group the + /// `priority` field needs to be used, otherwise the sort order is undefined. + /// + /// ### Known problems + /// Does not check lints inherited using `lints.workspace = true` /// /// ### Example /// ```toml - /// # The `Cargo.toml` with feature name redundancy - /// [features] - /// default = ["use-abc", "with-def", "ghi-support"] - /// use-abc = [] // redundant - /// with-def = [] // redundant - /// ghi-support = [] // redundant + /// # Passed as `--allow=clippy::similar_names --warn=clippy::pedantic` + /// # which results in `similar_names` being `warn` + /// [lints.clippy] + /// pedantic = "warn" + /// similar_names = "allow" /// ``` - /// /// Use instead: /// ```toml - /// [features] - /// default = ["abc", "def", "ghi"] - /// abc = [] - /// def = [] - /// ghi = [] + /// # Passed as `--warn=clippy::pedantic --allow=clippy::similar_names` + /// # which results in `similar_names` being `allow` + /// [lints.clippy] + /// pedantic = { level = "warn", priority = -1 } + /// similar_names = "allow" /// ``` + #[clippy::version = "1.78.0"] + pub LINT_GROUPS_PRIORITY, + correctness, + "a lint group in `Cargo.toml` at the same priority as a lint" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks to see if multiple versions of a crate are being + /// used. /// - #[clippy::version = "1.57.0"] - pub REDUNDANT_FEATURE_NAMES, + /// ### Why is this bad? + /// This bloats the size of targets, and can lead to + /// confusing error messages when structs or traits are used interchangeably + /// between different versions of a crate. + /// + /// ### Known problems + /// Because this can be caused purely by the dependencies + /// themselves, it's not always possible to fix this issue. + /// In those cases, you can allow that specific crate using + /// the `allowed-duplicate-crates` configuration option. + /// + /// ### Example + /// ```toml + /// # This will pull in both winapi v0.3.x and v0.2.x, triggering a warning. + /// [dependencies] + /// ctrlc = "=3.1.0" + /// ansi_term = "=0.11.0" + /// ``` + #[clippy::version = "pre 1.29.0"] + pub MULTIPLE_CRATE_VERSIONS, cargo, - "usage of a redundant feature name" + "multiple versions of the same crate being used" } declare_clippy_lint! { @@ -120,31 +154,34 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks to see if multiple versions of a crate are being - /// used. + /// Checks for feature names with prefix `use-`, `with-` or suffix `-support` /// /// ### Why is this bad? - /// This bloats the size of targets, and can lead to - /// confusing error messages when structs or traits are used interchangeably - /// between different versions of a crate. - /// - /// ### Known problems - /// Because this can be caused purely by the dependencies - /// themselves, it's not always possible to fix this issue. - /// In those cases, you can allow that specific crate using - /// the `allowed-duplicate-crates` configuration option. + /// These prefixes and suffixes have no significant meaning. /// /// ### Example /// ```toml - /// # This will pull in both winapi v0.3.x and v0.2.x, triggering a warning. - /// [dependencies] - /// ctrlc = "=3.1.0" - /// ansi_term = "=0.11.0" + /// # The `Cargo.toml` with feature name redundancy + /// [features] + /// default = ["use-abc", "with-def", "ghi-support"] + /// use-abc = [] // redundant + /// with-def = [] // redundant + /// ghi-support = [] // redundant /// ``` - #[clippy::version = "pre 1.29.0"] - pub MULTIPLE_CRATE_VERSIONS, + /// + /// Use instead: + /// ```toml + /// [features] + /// default = ["abc", "def", "ghi"] + /// abc = [] + /// def = [] + /// ghi = [] + /// ``` + /// + #[clippy::version = "1.57.0"] + pub REDUNDANT_FEATURE_NAMES, cargo, - "multiple versions of the same crate being used" + "usage of a redundant feature name" } declare_clippy_lint! { @@ -176,48 +213,6 @@ declare_clippy_lint! { "wildcard dependencies being used" } -declare_clippy_lint! { - /// ### What it does - /// Checks for lint groups with the same priority as lints in the `Cargo.toml` - /// [`[lints]` table](https://doc.rust-lang.org/cargo/reference/manifest.html#the-lints-section). - /// - /// This lint will be removed once [cargo#12918](https://github.com/rust-lang/cargo/issues/12918) - /// is resolved. - /// - /// ### Why is this bad? - /// The order of lints in the `[lints]` is ignored, to have a lint override a group the - /// `priority` field needs to be used, otherwise the sort order is undefined. - /// - /// ### Known problems - /// Does not check lints inherited using `lints.workspace = true` - /// - /// ### Example - /// ```toml - /// # Passed as `--allow=clippy::similar_names --warn=clippy::pedantic` - /// # which results in `similar_names` being `warn` - /// [lints.clippy] - /// pedantic = "warn" - /// similar_names = "allow" - /// ``` - /// Use instead: - /// ```toml - /// # Passed as `--warn=clippy::pedantic --allow=clippy::similar_names` - /// # which results in `similar_names` being `allow` - /// [lints.clippy] - /// pedantic = { level = "warn", priority = -1 } - /// similar_names = "allow" - /// ``` - #[clippy::version = "1.78.0"] - pub LINT_GROUPS_PRIORITY, - correctness, - "a lint group in `Cargo.toml` at the same priority as a lint" -} - -pub struct Cargo { - allowed_duplicate_crates: FxHashSet, - ignore_publish: bool, -} - impl_lint_pass!(Cargo => [ CARGO_COMMON_METADATA, LINT_GROUPS_PRIORITY, @@ -227,6 +222,11 @@ impl_lint_pass!(Cargo => [ WILDCARD_DEPENDENCIES, ]); +pub struct Cargo { + allowed_duplicate_crates: FxHashSet, + ignore_publish: bool, +} + impl Cargo { pub fn new(conf: &'static Conf) -> Self { Self { diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 2e5e5dd252a4..75761de4ae73 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -36,440 +36,382 @@ use rustc_session::impl_lint_pass; declare_clippy_lint! { /// ### What it does - /// Checks for casts from any numeric type to a float type where - /// the receiving type cannot store all values from the original type without - /// rounding errors. This possible rounding is to be expected, so this lint is - /// `Allow` by default. - /// - /// Basically, this warns on casting any integer with 32 or more bits to `f32` - /// or any 64-bit integer to `f64`. + /// Checks for the usage of `as *const _` or `as *mut _` conversion using inferred type. /// - /// ### Why is this bad? - /// It's not bad at all. But in some applications it can be - /// helpful to know where precision loss can take place. This lint can help find - /// those places in the code. + /// ### Why restrict this? + /// The conversion might include a dangerous cast that might go undetected due to the type being inferred. /// /// ### Example /// ```no_run - /// let x = u64::MAX; - /// x as f64; + /// fn as_usize(t: &T) -> usize { + /// // BUG: `t` is already a reference, so we will here + /// // return a dangling pointer to a temporary value instead + /// &t as *const _ as usize + /// } /// ``` - #[clippy::version = "pre 1.29.0"] - pub CAST_PRECISION_LOSS, - pedantic, - "casts that cause loss of precision, e.g., `x as f32` where `x: u64`" + /// Use instead: + /// ```no_run + /// fn as_usize(t: &T) -> usize { + /// t as *const T as usize + /// } + /// ``` + #[clippy::version = "1.85.0"] + pub AS_POINTER_UNDERSCORE, + restriction, + "detects `as *mut _` and `as *const _` conversion" } declare_clippy_lint! { /// ### What it does - /// Checks for casts from a signed to an unsigned numeric - /// type. In this case, negative values wrap around to large positive values, - /// which can be quite surprising in practice. However, since the cast works as - /// defined, this lint is `Allow` by default. + /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer. /// /// ### Why is this bad? - /// Possibly surprising results. You can activate this lint - /// as a one-time check to see where numeric wrapping can arise. + /// Since `as_ptr` takes a `&self`, the pointer won't have write permissions unless interior + /// mutability is used, making it unlikely that having it as a mutable pointer is correct. /// /// ### Example /// ```no_run - /// let y: i8 = -1; - /// y as u64; // will return 18446744073709551615 + /// let mut vec = Vec::::with_capacity(1); + /// let ptr = vec.as_ptr() as *mut u8; + /// unsafe { ptr.write(4) }; // UNDEFINED BEHAVIOUR /// ``` - #[clippy::version = "pre 1.29.0"] - pub CAST_SIGN_LOSS, - pedantic, - "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`" + /// Use instead: + /// ```no_run + /// let mut vec = Vec::::with_capacity(1); + /// let ptr = vec.as_mut_ptr(); + /// unsafe { ptr.write(4) }; + /// ``` + #[clippy::version = "1.66.0"] + pub AS_PTR_CAST_MUT, + nursery, + "casting the result of the `&self`-taking `as_ptr` to a mutable pointer" } declare_clippy_lint! { /// ### What it does - /// Checks for casts between numeric types that may - /// truncate large values. This is expected behavior, so the cast is `Allow` by - /// default. It suggests user either explicitly ignore the lint, - /// or use `try_from()` and handle the truncation, default, or panic explicitly. + /// Checks for the usage of `as _` conversion using inferred type. /// - /// ### Why is this bad? - /// In some problem domains, it is good practice to avoid - /// truncation. This lint can be activated to help assess where additional - /// checks could be beneficial. + /// ### Why restrict this? + /// The conversion might include lossy conversion or a dangerous cast that might go + /// undetected due to the type being inferred. + /// + /// The lint is allowed by default as using `_` is less wordy than always specifying the type. /// /// ### Example /// ```no_run - /// fn as_u8(x: u64) -> u8 { - /// x as u8 - /// } + /// fn foo(n: usize) {} + /// let n: u16 = 256; + /// foo(n as _); /// ``` /// Use instead: /// ```no_run - /// fn as_u8(x: u64) -> u8 { - /// if let Ok(x) = u8::try_from(x) { - /// x - /// } else { - /// todo!(); - /// } - /// } - /// // Or - /// #[allow(clippy::cast_possible_truncation)] - /// fn as_u16(x: u64) -> u16 { - /// x as u16 - /// } + /// fn foo(n: usize) {} + /// let n: u16 = 256; + /// foo(n as usize); /// ``` - #[clippy::version = "pre 1.29.0"] - pub CAST_POSSIBLE_TRUNCATION, - pedantic, - "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`" + #[clippy::version = "1.63.0"] + pub AS_UNDERSCORE, + restriction, + "detects `as _` conversion" } declare_clippy_lint! { /// ### What it does - /// Checks for casts from an unsigned type to a signed type of - /// the same size, or possibly smaller due to target-dependent integers. - /// Performing such a cast is a no-op for the compiler (that is, nothing is - /// changed at the bit level), and the binary representation of the value is - /// reinterpreted. This can cause wrapping if the value is too big - /// for the target signed type. However, the cast works as defined, so this lint - /// is `Allow` by default. + /// Checks for the usage of `&expr as *const T` or + /// `&mut expr as *mut T`, and suggest using `&raw const` or + /// `&raw mut` instead. /// /// ### Why is this bad? - /// While such a cast is not bad in itself, the results can - /// be surprising when this is not the intended behavior: + /// This would improve readability and avoid creating a reference + /// that points to an uninitialized value or unaligned place. + /// Read the `&raw` explanation in the Reference for more information. /// /// ### Example /// ```no_run - /// let _ = u32::MAX as i32; // will yield a value of `-1` - /// ``` + /// let val = 1; + /// let p = &val as *const i32; /// + /// let mut val_mut = 1; + /// let p_mut = &mut val_mut as *mut i32; + /// ``` /// Use instead: /// ```no_run - /// let _ = i32::try_from(u32::MAX).ok(); - /// ``` + /// let val = 1; + /// let p = &raw const val; /// - /// If the wrapping is intended, you can use: - /// ```no_run - /// let _ = u32::MAX.cast_signed(); - /// let _ = (-1i32).cast_unsigned(); + /// let mut val_mut = 1; + /// let p_mut = &raw mut val_mut; /// ``` - /// - #[clippy::version = "pre 1.29.0"] - pub CAST_POSSIBLE_WRAP, + #[clippy::version = "1.60.0"] + pub BORROW_AS_PTR, pedantic, - "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`" + "borrowing just to cast to a raw pointer" } declare_clippy_lint! { /// ### What it does - /// Checks for casts between numeric types that can be replaced by safe - /// conversion functions. + /// Checks for usage of the `abs()` method that cast the result to unsigned. /// /// ### Why is this bad? - /// Rust's `as` keyword will perform many kinds of conversions, including - /// silently lossy conversions. Conversion functions such as `i32::from` - /// will only perform lossless conversions. Using the conversion functions - /// prevents conversions from becoming silently lossy if the input types - /// ever change, and makes it clear for people reading the code that the - /// conversion is lossless. + /// The `unsigned_abs()` method avoids panic when called on the MIN value. /// /// ### Example /// ```no_run - /// fn as_u64(x: u8) -> u64 { - /// x as u64 - /// } + /// let x: i32 = -42; + /// let y: u32 = x.abs() as u32; /// ``` - /// - /// Using `::from` would look like this: - /// + /// Use instead: /// ```no_run - /// fn as_u64(x: u8) -> u64 { - /// u64::from(x) - /// } + /// let x: i32 = -42; + /// let y: u32 = x.unsigned_abs(); /// ``` - #[clippy::version = "pre 1.29.0"] - pub CAST_LOSSLESS, - pedantic, - "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`" + #[clippy::version = "1.62.0"] + pub CAST_ABS_TO_UNSIGNED, + suspicious, + "casting the result of `abs()` to an unsigned integer can panic" } declare_clippy_lint! { /// ### What it does - /// Checks for casts to the same type, casts of int literals to integer - /// types, casts of float literals to float types, and casts between raw - /// pointers that don't change type or constness. + /// Checks for casts from an enum tuple constructor to an integer. /// /// ### Why is this bad? - /// It's just unnecessary. - /// - /// ### Known problems - /// When the expression on the left is a function call, the lint considers - /// the return type to be a type alias if it's aliased through a `use` - /// statement (like `use std::io::Result as IoResult`). It will not lint - /// such cases. - /// - /// This check will only work on primitive types without any intermediate - /// references: raw pointers and trait objects may or may not work. + /// The cast is easily confused with casting a c-like enum value to an integer. /// /// ### Example /// ```no_run - /// let _ = 2i32 as i32; - /// let _ = 0.5 as f32; - /// ``` - /// - /// Better: - /// - /// ```no_run - /// let _ = 2_i32; - /// let _ = 0.5_f32; + /// enum E { X(i32) }; + /// let _ = E::X as usize; /// ``` - #[clippy::version = "pre 1.29.0"] - pub UNNECESSARY_CAST, - complexity, - "cast to the same type, e.g., `x as i32` where `x: i32`" + #[clippy::version = "1.61.0"] + pub CAST_ENUM_CONSTRUCTOR, + suspicious, + "casts from an enum tuple constructor to an integer" } declare_clippy_lint! { /// ### What it does - /// Checks for casts, using `as` or `pointer::cast`, from a - /// less strictly aligned pointer to a more strictly aligned pointer. + /// Checks for casts from an enum type to an integral type that will definitely truncate the + /// value. /// /// ### Why is this bad? - /// Dereferencing the resulting pointer may be undefined behavior. - /// - /// ### Known problems - /// Using [`std::ptr::read_unaligned`](https://doc.rust-lang.org/std/ptr/fn.read_unaligned.html) and [`std::ptr::write_unaligned`](https://doc.rust-lang.org/std/ptr/fn.write_unaligned.html) or - /// similar on the resulting pointer is fine. Is over-zealous: casts with - /// manual alignment checks or casts like `u64` -> `u8` -> `u16` can be - /// fine. Miri is able to do a more in-depth analysis. + /// The resulting integral value will not match the value of the variant it came from. /// /// ### Example /// ```no_run - /// let _ = (&1u8 as *const u8) as *const u16; - /// let _ = (&mut 1u8 as *mut u8) as *mut u16; - /// - /// (&1u8 as *const u8).cast::(); - /// (&mut 1u8 as *mut u8).cast::(); + /// enum E { X = 256 }; + /// let _ = E::X as u8; /// ``` - #[clippy::version = "pre 1.29.0"] - pub CAST_PTR_ALIGNMENT, - pedantic, - "cast from a pointer to a more strictly aligned pointer" + #[clippy::version = "1.61.0"] + pub CAST_ENUM_TRUNCATION, + suspicious, + "casts from an enum type to an integral type that will truncate the value" } declare_clippy_lint! { /// ### What it does - /// Checks for casts of function pointers to something other than `usize`. + /// Checks for casts between numeric types that can be replaced by safe + /// conversion functions. /// /// ### Why is this bad? - /// Casting a function pointer to anything other than `usize`/`isize` is - /// not portable across architectures. If the target type is too small the - /// address would be truncated, and target types larger than `usize` are - /// unnecessary. - /// - /// Casting to `isize` also doesn't make sense, since addresses are never - /// signed. + /// Rust's `as` keyword will perform many kinds of conversions, including + /// silently lossy conversions. Conversion functions such as `i32::from` + /// will only perform lossless conversions. Using the conversion functions + /// prevents conversions from becoming silently lossy if the input types + /// ever change, and makes it clear for people reading the code that the + /// conversion is lossless. /// /// ### Example /// ```no_run - /// fn fun() -> i32 { 1 } - /// let _ = fun as i64; + /// fn as_u64(x: u8) -> u64 { + /// x as u64 + /// } /// ``` /// - /// Use instead: + /// Using `::from` would look like this: + /// /// ```no_run - /// # fn fun() -> i32 { 1 } - /// let _ = fun as usize; + /// fn as_u64(x: u8) -> u64 { + /// u64::from(x) + /// } /// ``` #[clippy::version = "pre 1.29.0"] - pub FN_TO_NUMERIC_CAST, - style, - "casting a function pointer to a numeric type other than `usize`" + pub CAST_LOSSLESS, + pedantic, + "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`" } declare_clippy_lint! { /// ### What it does - /// Checks for casts of a function pointer to a numeric type not wide enough to - /// store an address. + /// Checks for a known NaN float being cast to an integer /// /// ### Why is this bad? - /// Such a cast discards some bits of the function's address. If this is intended, it would be more - /// clearly expressed by casting to `usize` first, then casting the `usize` to the intended type (with - /// a comment) to perform the truncation. + /// NaNs are cast into zero, so one could simply use this and make the + /// code more readable. The lint could also hint at a programmer error. /// /// ### Example - /// ```no_run - /// fn fn1() -> i16 { - /// 1 - /// }; - /// let _ = fn1 as i32; + /// ```rust,ignore + /// let _ = (0.0_f32 / 0.0) as u64; /// ``` - /// /// Use instead: - /// ```no_run - /// // Cast to usize first, then comment with the reason for the truncation - /// fn fn1() -> i16 { - /// 1 - /// }; - /// let fn_ptr = fn1 as usize; - /// let fn_ptr_truncated = fn_ptr as i32; + /// ```rust,ignore + /// let _ = 0_u64; /// ``` - #[clippy::version = "pre 1.29.0"] - pub FN_TO_NUMERIC_CAST_WITH_TRUNCATION, - style, - "casting a function pointer to a numeric type not wide enough to store the address" + #[clippy::version = "1.66.0"] + pub CAST_NAN_TO_INT, + suspicious, + "casting a known floating-point NaN into an integer" } declare_clippy_lint! { /// ### What it does - /// Checks for casts of a function pointer to any integer type. + /// Checks for casts between numeric types that may + /// truncate large values. This is expected behavior, so the cast is `Allow` by + /// default. It suggests user either explicitly ignore the lint, + /// or use `try_from()` and handle the truncation, default, or panic explicitly. /// - /// ### Why restrict this? - /// Casting a function pointer to an integer can have surprising results and can occur - /// accidentally if parentheses are omitted from a function call. If you aren't doing anything - /// low-level with function pointers then you can opt out of casting functions to integers in - /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function - /// pointer casts in your code. + /// ### Why is this bad? + /// In some problem domains, it is good practice to avoid + /// truncation. This lint can be activated to help assess where additional + /// checks could be beneficial. /// /// ### Example /// ```no_run - /// // fn1 is cast as `usize` - /// fn fn1() -> u16 { - /// 1 - /// }; - /// let _ = fn1 as usize; + /// fn as_u8(x: u64) -> u8 { + /// x as u8 + /// } /// ``` - /// /// Use instead: /// ```no_run - /// // maybe you intended to call the function? - /// fn fn2() -> u16 { - /// 1 - /// }; - /// let _ = fn2() as usize; - /// - /// // or - /// - /// // maybe you intended to cast it to a function type? - /// fn fn3() -> u16 { - /// 1 + /// fn as_u8(x: u64) -> u8 { + /// if let Ok(x) = u8::try_from(x) { + /// x + /// } else { + /// todo!(); + /// } + /// } + /// // Or + /// #[allow(clippy::cast_possible_truncation)] + /// fn as_u16(x: u64) -> u16 { + /// x as u16 /// } - /// let _ = fn3 as fn() -> u16; /// ``` - #[clippy::version = "1.58.0"] - pub FN_TO_NUMERIC_CAST_ANY, - restriction, - "casting a function pointer to any integer type" + #[clippy::version = "pre 1.29.0"] + pub CAST_POSSIBLE_TRUNCATION, + pedantic, + "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`" } declare_clippy_lint! { /// ### What it does - /// Checks for expressions where a character literal is cast - /// to `u8` and suggests using a byte literal instead. + /// Checks for casts from an unsigned type to a signed type of + /// the same size, or possibly smaller due to target-dependent integers. + /// Performing such a cast is a no-op for the compiler (that is, nothing is + /// changed at the bit level), and the binary representation of the value is + /// reinterpreted. This can cause wrapping if the value is too big + /// for the target signed type. However, the cast works as defined, so this lint + /// is `Allow` by default. /// /// ### Why is this bad? - /// In general, casting values to smaller types is - /// error-prone and should be avoided where possible. In the particular case of - /// converting a character literal to `u8`, it is easy to avoid by just using a - /// byte literal instead. As an added bonus, `b'a'` is also slightly shorter - /// than `'a' as u8`. + /// While such a cast is not bad in itself, the results can + /// be surprising when this is not the intended behavior: /// /// ### Example - /// ```rust,ignore - /// 'x' as u8 + /// ```no_run + /// let _ = u32::MAX as i32; // will yield a value of `-1` /// ``` /// - /// A better version, using the byte literal: + /// Use instead: + /// ```no_run + /// let _ = i32::try_from(u32::MAX).ok(); + /// ``` /// - /// ```rust,ignore - /// b'x' + /// If the wrapping is intended, you can use: + /// ```no_run + /// let _ = u32::MAX.cast_signed(); + /// let _ = (-1i32).cast_unsigned(); /// ``` + /// #[clippy::version = "pre 1.29.0"] - pub CHAR_LIT_AS_U8, - complexity, - "casting a character literal to `u8` truncates" + pub CAST_POSSIBLE_WRAP, + pedantic, + "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`" } declare_clippy_lint! { /// ### What it does - /// Checks for `as` casts between raw pointers that don't change their - /// constness, namely `*const T` to `*const U` and `*mut T` to `*mut U`. + /// Checks for casts from any numeric type to a float type where + /// the receiving type cannot store all values from the original type without + /// rounding errors. This possible rounding is to be expected, so this lint is + /// `Allow` by default. + /// + /// Basically, this warns on casting any integer with 32 or more bits to `f32` + /// or any 64-bit integer to `f64`. /// /// ### Why is this bad? - /// Though `as` casts between raw pointers are not terrible, - /// `pointer::cast` is safer because it cannot accidentally change the - /// pointer's mutability, nor cast the pointer to other types like `usize`. + /// It's not bad at all. But in some applications it can be + /// helpful to know where precision loss can take place. This lint can help find + /// those places in the code. /// /// ### Example /// ```no_run - /// let ptr: *const u32 = &42_u32; - /// let mut_ptr: *mut u32 = &mut 42_u32; - /// let _ = ptr as *const i32; - /// let _ = mut_ptr as *mut i32; - /// ``` - /// Use instead: - /// ```no_run - /// let ptr: *const u32 = &42_u32; - /// let mut_ptr: *mut u32 = &mut 42_u32; - /// let _ = ptr.cast::(); - /// let _ = mut_ptr.cast::(); + /// let x = u64::MAX; + /// x as f64; /// ``` - #[clippy::version = "1.51.0"] - pub PTR_AS_PTR, + #[clippy::version = "pre 1.29.0"] + pub CAST_PRECISION_LOSS, pedantic, - "casting using `as` between raw pointers that doesn't change their constness, where `pointer::cast` could take the place of `as`" + "casts that cause loss of precision, e.g., `x as f32` where `x: u64`" } declare_clippy_lint! { /// ### What it does - /// Checks for `as` casts between raw pointers that change their constness, namely `*const T` to - /// `*mut T` and `*mut T` to `*const T`. + /// Checks for casts, using `as` or `pointer::cast`, from a + /// less strictly aligned pointer to a more strictly aligned pointer. /// /// ### Why is this bad? - /// Though `as` casts between raw pointers are not terrible, `pointer::cast_mut` and - /// `pointer::cast_const` are safer because they cannot accidentally cast the pointer to another - /// type. Or, when null pointers are involved, `null()` and `null_mut()` can be used directly. + /// Dereferencing the resulting pointer may be undefined behavior. + /// + /// ### Known problems + /// Using [`std::ptr::read_unaligned`](https://doc.rust-lang.org/std/ptr/fn.read_unaligned.html) and [`std::ptr::write_unaligned`](https://doc.rust-lang.org/std/ptr/fn.write_unaligned.html) or + /// similar on the resulting pointer is fine. Is over-zealous: casts with + /// manual alignment checks or casts like `u64` -> `u8` -> `u16` can be + /// fine. Miri is able to do a more in-depth analysis. /// /// ### Example /// ```no_run - /// let ptr: *const u32 = &42_u32; - /// let mut_ptr = ptr as *mut u32; - /// let ptr = mut_ptr as *const u32; - /// let ptr1 = std::ptr::null::() as *mut u32; - /// let ptr2 = std::ptr::null_mut::() as *const u32; - /// let ptr3 = std::ptr::null::().cast_mut(); - /// let ptr4 = std::ptr::null_mut::().cast_const(); - /// ``` - /// Use instead: - /// ```no_run - /// let ptr: *const u32 = &42_u32; - /// let mut_ptr = ptr.cast_mut(); - /// let ptr = mut_ptr.cast_const(); - /// let ptr1 = std::ptr::null_mut::(); - /// let ptr2 = std::ptr::null::(); - /// let ptr3 = std::ptr::null_mut::(); - /// let ptr4 = std::ptr::null::(); + /// let _ = (&1u8 as *const u8) as *const u16; + /// let _ = (&mut 1u8 as *mut u8) as *mut u16; + /// + /// (&1u8 as *const u8).cast::(); + /// (&mut 1u8 as *mut u8).cast::(); /// ``` - #[clippy::version = "1.72.0"] - pub PTR_CAST_CONSTNESS, + #[clippy::version = "pre 1.29.0"] + pub CAST_PTR_ALIGNMENT, pedantic, - "casting using `as` on raw pointers to change constness when specialized methods apply" + "cast from a pointer to a more strictly aligned pointer" } declare_clippy_lint! { /// ### What it does - /// Checks for casts from an enum type to an integral type that will definitely truncate the - /// value. + /// Checks for casts from a signed to an unsigned numeric + /// type. In this case, negative values wrap around to large positive values, + /// which can be quite surprising in practice. However, since the cast works as + /// defined, this lint is `Allow` by default. /// /// ### Why is this bad? - /// The resulting integral value will not match the value of the variant it came from. + /// Possibly surprising results. You can activate this lint + /// as a one-time check to see where numeric wrapping can arise. /// /// ### Example /// ```no_run - /// enum E { X = 256 }; - /// let _ = E::X as u8; + /// let y: i8 = -1; + /// y as u64; // will return 18446744073709551615 /// ``` - #[clippy::version = "1.61.0"] - pub CAST_ENUM_TRUNCATION, - suspicious, - "casts from an enum type to an integral type that will truncate the value" + #[clippy::version = "pre 1.29.0"] + pub CAST_SIGN_LOSS, + pedantic, + "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`" } declare_clippy_lint! { @@ -519,341 +461,389 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts from an enum tuple constructor to an integer. + /// Checks for a raw slice being cast to a slice pointer /// /// ### Why is this bad? - /// The cast is easily confused with casting a c-like enum value to an integer. + /// This can result in multiple `&mut` references to the same location when only a pointer is + /// required. + /// `ptr::slice_from_raw_parts` is a safe alternative that doesn't require + /// the same [safety requirements] to be upheld. /// /// ### Example - /// ```no_run - /// enum E { X(i32) }; - /// let _ = E::X as usize; + /// ```rust,ignore + /// let _: *const [u8] = std::slice::from_raw_parts(ptr, len) as *const _; + /// let _: *mut [u8] = std::slice::from_raw_parts_mut(ptr, len) as *mut _; /// ``` - #[clippy::version = "1.61.0"] - pub CAST_ENUM_CONSTRUCTOR, + /// Use instead: + /// ```rust,ignore + /// let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, len); + /// let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len); + /// ``` + /// [safety requirements]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety + #[clippy::version = "1.65.0"] + pub CAST_SLICE_FROM_RAW_PARTS, suspicious, - "casts from an enum tuple constructor to an integer" + "casting a slice created from a pointer and length to a slice pointer" } declare_clippy_lint! { /// ### What it does - /// Checks for usage of the `abs()` method that cast the result to unsigned. + /// Checks for expressions where a character literal is cast + /// to `u8` and suggests using a byte literal instead. /// /// ### Why is this bad? - /// The `unsigned_abs()` method avoids panic when called on the MIN value. + /// In general, casting values to smaller types is + /// error-prone and should be avoided where possible. In the particular case of + /// converting a character literal to `u8`, it is easy to avoid by just using a + /// byte literal instead. As an added bonus, `b'a'` is also slightly shorter + /// than `'a' as u8`. /// /// ### Example - /// ```no_run - /// let x: i32 = -42; - /// let y: u32 = x.abs() as u32; + /// ```rust,ignore + /// 'x' as u8 /// ``` - /// Use instead: - /// ```no_run - /// let x: i32 = -42; - /// let y: u32 = x.unsigned_abs(); + /// + /// A better version, using the byte literal: + /// + /// ```rust,ignore + /// b'x' /// ``` - #[clippy::version = "1.62.0"] - pub CAST_ABS_TO_UNSIGNED, - suspicious, - "casting the result of `abs()` to an unsigned integer can panic" + #[clippy::version = "pre 1.29.0"] + pub CHAR_LIT_AS_U8, + complexity, + "casting a character literal to `u8` truncates" } declare_clippy_lint! { /// ### What it does - /// Checks for the usage of `as _` conversion using inferred type. + /// Checks for casts of a primitive method pointer like `max`/`min` to any integer type. /// /// ### Why restrict this? - /// The conversion might include lossy conversion or a dangerous cast that might go - /// undetected due to the type being inferred. - /// - /// The lint is allowed by default as using `_` is less wordy than always specifying the type. + /// Casting a function pointer to an integer can have surprising results and can occur + /// accidentally if parentheses are omitted from a function call. If you aren't doing anything + /// low-level with function pointers then you can opt out of casting functions to integers in + /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function + /// pointer casts in your code. /// /// ### Example /// ```no_run - /// fn foo(n: usize) {} - /// let n: u16 = 256; - /// foo(n as _); + /// let _ = u16::max as usize; /// ``` + /// /// Use instead: /// ```no_run - /// fn foo(n: usize) {} - /// let n: u16 = 256; - /// foo(n as usize); + /// let _ = u16::MAX as usize; /// ``` - #[clippy::version = "1.63.0"] - pub AS_UNDERSCORE, - restriction, - "detects `as _` conversion" + #[clippy::version = "1.89.0"] + pub CONFUSING_METHOD_TO_NUMERIC_CAST, + suspicious, + "casting a primitive method pointer to any integer type" } declare_clippy_lint! { /// ### What it does - /// Checks for the usage of `&expr as *const T` or - /// `&mut expr as *mut T`, and suggest using `&raw const` or - /// `&raw mut` instead. + /// Checks for casts of function pointers to something other than `usize`. /// /// ### Why is this bad? - /// This would improve readability and avoid creating a reference - /// that points to an uninitialized value or unaligned place. - /// Read the `&raw` explanation in the Reference for more information. + /// Casting a function pointer to anything other than `usize`/`isize` is + /// not portable across architectures. If the target type is too small the + /// address would be truncated, and target types larger than `usize` are + /// unnecessary. + /// + /// Casting to `isize` also doesn't make sense, since addresses are never + /// signed. /// /// ### Example /// ```no_run - /// let val = 1; - /// let p = &val as *const i32; - /// - /// let mut val_mut = 1; - /// let p_mut = &mut val_mut as *mut i32; + /// fn fun() -> i32 { 1 } + /// let _ = fun as i64; /// ``` + /// /// Use instead: /// ```no_run - /// let val = 1; - /// let p = &raw const val; - /// - /// let mut val_mut = 1; - /// let p_mut = &raw mut val_mut; + /// # fn fun() -> i32 { 1 } + /// let _ = fun as usize; /// ``` - #[clippy::version = "1.60.0"] - pub BORROW_AS_PTR, - pedantic, - "borrowing just to cast to a raw pointer" + #[clippy::version = "pre 1.29.0"] + pub FN_TO_NUMERIC_CAST, + style, + "casting a function pointer to a numeric type other than `usize`" } declare_clippy_lint! { /// ### What it does - /// Checks for a raw slice being cast to a slice pointer + /// Checks for casts of a function pointer to any integer type. /// - /// ### Why is this bad? - /// This can result in multiple `&mut` references to the same location when only a pointer is - /// required. - /// `ptr::slice_from_raw_parts` is a safe alternative that doesn't require - /// the same [safety requirements] to be upheld. + /// ### Why restrict this? + /// Casting a function pointer to an integer can have surprising results and can occur + /// accidentally if parentheses are omitted from a function call. If you aren't doing anything + /// low-level with function pointers then you can opt out of casting functions to integers in + /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function + /// pointer casts in your code. /// /// ### Example - /// ```rust,ignore - /// let _: *const [u8] = std::slice::from_raw_parts(ptr, len) as *const _; - /// let _: *mut [u8] = std::slice::from_raw_parts_mut(ptr, len) as *mut _; + /// ```no_run + /// // fn1 is cast as `usize` + /// fn fn1() -> u16 { + /// 1 + /// }; + /// let _ = fn1 as usize; /// ``` + /// /// Use instead: - /// ```rust,ignore - /// let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, len); - /// let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len); - /// ``` - /// [safety requirements]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety - #[clippy::version = "1.65.0"] - pub CAST_SLICE_FROM_RAW_PARTS, - suspicious, - "casting a slice created from a pointer and length to a slice pointer" + /// ```no_run + /// // maybe you intended to call the function? + /// fn fn2() -> u16 { + /// 1 + /// }; + /// let _ = fn2() as usize; + /// + /// // or + /// + /// // maybe you intended to cast it to a function type? + /// fn fn3() -> u16 { + /// 1 + /// } + /// let _ = fn3 as fn() -> u16; + /// ``` + #[clippy::version = "1.58.0"] + pub FN_TO_NUMERIC_CAST_ANY, + restriction, + "casting a function pointer to any integer type" } declare_clippy_lint! { /// ### What it does - /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer. + /// Checks for casts of a function pointer to a numeric type not wide enough to + /// store an address. /// /// ### Why is this bad? - /// Since `as_ptr` takes a `&self`, the pointer won't have write permissions unless interior - /// mutability is used, making it unlikely that having it as a mutable pointer is correct. + /// Such a cast discards some bits of the function's address. If this is intended, it would be more + /// clearly expressed by casting to `usize` first, then casting the `usize` to the intended type (with + /// a comment) to perform the truncation. /// /// ### Example /// ```no_run - /// let mut vec = Vec::::with_capacity(1); - /// let ptr = vec.as_ptr() as *mut u8; - /// unsafe { ptr.write(4) }; // UNDEFINED BEHAVIOUR + /// fn fn1() -> i16 { + /// 1 + /// }; + /// let _ = fn1 as i32; /// ``` + /// /// Use instead: /// ```no_run - /// let mut vec = Vec::::with_capacity(1); - /// let ptr = vec.as_mut_ptr(); - /// unsafe { ptr.write(4) }; + /// // Cast to usize first, then comment with the reason for the truncation + /// fn fn1() -> i16 { + /// 1 + /// }; + /// let fn_ptr = fn1 as usize; + /// let fn_ptr_truncated = fn_ptr as i32; /// ``` - #[clippy::version = "1.66.0"] - pub AS_PTR_CAST_MUT, - nursery, - "casting the result of the `&self`-taking `as_ptr` to a mutable pointer" + #[clippy::version = "pre 1.29.0"] + pub FN_TO_NUMERIC_CAST_WITH_TRUNCATION, + style, + "casting a function pointer to a numeric type not wide enough to store the address" } declare_clippy_lint! { /// ### What it does - /// Checks for a known NaN float being cast to an integer + /// Checks for casts of small constant literals or `mem::align_of` results to raw pointers. /// /// ### Why is this bad? - /// NaNs are cast into zero, so one could simply use this and make the - /// code more readable. The lint could also hint at a programmer error. + /// This creates a dangling pointer and is better expressed as + /// {`std`, `core`}`::ptr::`{`dangling`, `dangling_mut`}. /// /// ### Example - /// ```rust,ignore - /// let _ = (0.0_f32 / 0.0) as u64; + /// ```no_run + /// let ptr = 4 as *const u32; + /// let aligned = std::mem::align_of::() as *const u32; + /// let mut_ptr: *mut i64 = 8 as *mut _; /// ``` /// Use instead: - /// ```rust,ignore - /// let _ = 0_u64; + /// ```no_run + /// let ptr = std::ptr::dangling::(); + /// let aligned = std::ptr::dangling::(); + /// let mut_ptr: *mut i64 = std::ptr::dangling_mut(); /// ``` - #[clippy::version = "1.66.0"] - pub CAST_NAN_TO_INT, - suspicious, - "casting a known floating-point NaN into an integer" + #[clippy::version = "1.88.0"] + pub MANUAL_DANGLING_PTR, + style, + "casting small constant literals to pointers to create dangling pointers" } declare_clippy_lint! { /// ### What it does - /// Catch casts from `0` to some pointer type + /// Checks for bindings (constants, statics, or let bindings) that are defined + /// with one numeric type but are consistently cast to a different type in all usages. /// /// ### Why is this bad? - /// This generally means `null` and is better expressed as - /// {`std`, `core`}`::ptr::`{`null`, `null_mut`}. + /// If a binding is always cast to a different type when used, it would be clearer + /// and more efficient to define it with the target type from the start. /// /// ### Example /// ```no_run - /// let a = 0 as *const u32; + /// const SIZE: u16 = 15; + /// let arr: [u8; SIZE as usize] = [0; SIZE as usize]; /// ``` /// /// Use instead: /// ```no_run - /// let a = std::ptr::null::(); + /// const SIZE: usize = 15; + /// let arr: [u8; SIZE] = [0; SIZE]; /// ``` - #[clippy::version = "pre 1.29.0"] - pub ZERO_PTR, - style, - "using `0 as *{const, mut} T`" + #[clippy::version = "1.93.0"] + pub NEEDLESS_TYPE_CAST, + nursery, + "binding defined with one type but always cast to another" } declare_clippy_lint! { /// ### What it does - /// Checks for casts of references to pointer using `as` - /// and suggests `std::ptr::from_ref` and `std::ptr::from_mut` instead. + /// Checks for `as` casts between raw pointers that don't change their + /// constness, namely `*const T` to `*const U` and `*mut T` to `*mut U`. /// /// ### Why is this bad? - /// Using `as` casts may result in silently changing mutability or type. + /// Though `as` casts between raw pointers are not terrible, + /// `pointer::cast` is safer because it cannot accidentally change the + /// pointer's mutability, nor cast the pointer to other types like `usize`. /// /// ### Example /// ```no_run - /// let a_ref = &1; - /// let a_ptr = a_ref as *const _; + /// let ptr: *const u32 = &42_u32; + /// let mut_ptr: *mut u32 = &mut 42_u32; + /// let _ = ptr as *const i32; + /// let _ = mut_ptr as *mut i32; /// ``` /// Use instead: /// ```no_run - /// let a_ref = &1; - /// let a_ptr = std::ptr::from_ref(a_ref); + /// let ptr: *const u32 = &42_u32; + /// let mut_ptr: *mut u32 = &mut 42_u32; + /// let _ = ptr.cast::(); + /// let _ = mut_ptr.cast::(); /// ``` - #[clippy::version = "1.78.0"] - pub REF_AS_PTR, + #[clippy::version = "1.51.0"] + pub PTR_AS_PTR, pedantic, - "using `as` to cast a reference to pointer" + "casting using `as` between raw pointers that doesn't change their constness, where `pointer::cast` could take the place of `as`" } declare_clippy_lint! { /// ### What it does - /// Checks for the usage of `as *const _` or `as *mut _` conversion using inferred type. + /// Checks for `as` casts between raw pointers that change their constness, namely `*const T` to + /// `*mut T` and `*mut T` to `*const T`. /// - /// ### Why restrict this? - /// The conversion might include a dangerous cast that might go undetected due to the type being inferred. + /// ### Why is this bad? + /// Though `as` casts between raw pointers are not terrible, `pointer::cast_mut` and + /// `pointer::cast_const` are safer because they cannot accidentally cast the pointer to another + /// type. Or, when null pointers are involved, `null()` and `null_mut()` can be used directly. /// /// ### Example /// ```no_run - /// fn as_usize(t: &T) -> usize { - /// // BUG: `t` is already a reference, so we will here - /// // return a dangling pointer to a temporary value instead - /// &t as *const _ as usize - /// } + /// let ptr: *const u32 = &42_u32; + /// let mut_ptr = ptr as *mut u32; + /// let ptr = mut_ptr as *const u32; + /// let ptr1 = std::ptr::null::() as *mut u32; + /// let ptr2 = std::ptr::null_mut::() as *const u32; + /// let ptr3 = std::ptr::null::().cast_mut(); + /// let ptr4 = std::ptr::null_mut::().cast_const(); /// ``` /// Use instead: /// ```no_run - /// fn as_usize(t: &T) -> usize { - /// t as *const T as usize - /// } + /// let ptr: *const u32 = &42_u32; + /// let mut_ptr = ptr.cast_mut(); + /// let ptr = mut_ptr.cast_const(); + /// let ptr1 = std::ptr::null_mut::(); + /// let ptr2 = std::ptr::null::(); + /// let ptr3 = std::ptr::null_mut::(); + /// let ptr4 = std::ptr::null::(); /// ``` - #[clippy::version = "1.85.0"] - pub AS_POINTER_UNDERSCORE, - restriction, - "detects `as *mut _` and `as *const _` conversion" + #[clippy::version = "1.72.0"] + pub PTR_CAST_CONSTNESS, + pedantic, + "casting using `as` on raw pointers to change constness when specialized methods apply" } declare_clippy_lint! { /// ### What it does - /// Checks for casts of small constant literals or `mem::align_of` results to raw pointers. + /// Checks for casts of references to pointer using `as` + /// and suggests `std::ptr::from_ref` and `std::ptr::from_mut` instead. /// /// ### Why is this bad? - /// This creates a dangling pointer and is better expressed as - /// {`std`, `core`}`::ptr::`{`dangling`, `dangling_mut`}. + /// Using `as` casts may result in silently changing mutability or type. /// /// ### Example /// ```no_run - /// let ptr = 4 as *const u32; - /// let aligned = std::mem::align_of::() as *const u32; - /// let mut_ptr: *mut i64 = 8 as *mut _; + /// let a_ref = &1; + /// let a_ptr = a_ref as *const _; /// ``` /// Use instead: /// ```no_run - /// let ptr = std::ptr::dangling::(); - /// let aligned = std::ptr::dangling::(); - /// let mut_ptr: *mut i64 = std::ptr::dangling_mut(); + /// let a_ref = &1; + /// let a_ptr = std::ptr::from_ref(a_ref); /// ``` - #[clippy::version = "1.88.0"] - pub MANUAL_DANGLING_PTR, - style, - "casting small constant literals to pointers to create dangling pointers" + #[clippy::version = "1.78.0"] + pub REF_AS_PTR, + pedantic, + "using `as` to cast a reference to pointer" } declare_clippy_lint! { /// ### What it does - /// Checks for casts of a primitive method pointer like `max`/`min` to any integer type. + /// Checks for casts to the same type, casts of int literals to integer + /// types, casts of float literals to float types, and casts between raw + /// pointers that don't change type or constness. /// - /// ### Why restrict this? - /// Casting a function pointer to an integer can have surprising results and can occur - /// accidentally if parentheses are omitted from a function call. If you aren't doing anything - /// low-level with function pointers then you can opt out of casting functions to integers in - /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function - /// pointer casts in your code. + /// ### Why is this bad? + /// It's just unnecessary. + /// + /// ### Known problems + /// When the expression on the left is a function call, the lint considers + /// the return type to be a type alias if it's aliased through a `use` + /// statement (like `use std::io::Result as IoResult`). It will not lint + /// such cases. + /// + /// This check will only work on primitive types without any intermediate + /// references: raw pointers and trait objects may or may not work. /// /// ### Example /// ```no_run - /// let _ = u16::max as usize; + /// let _ = 2i32 as i32; + /// let _ = 0.5 as f32; /// ``` /// - /// Use instead: + /// Better: + /// /// ```no_run - /// let _ = u16::MAX as usize; + /// let _ = 2_i32; + /// let _ = 0.5_f32; /// ``` - #[clippy::version = "1.89.0"] - pub CONFUSING_METHOD_TO_NUMERIC_CAST, - suspicious, - "casting a primitive method pointer to any integer type" + #[clippy::version = "pre 1.29.0"] + pub UNNECESSARY_CAST, + complexity, + "cast to the same type, e.g., `x as i32` where `x: i32`" } declare_clippy_lint! { /// ### What it does - /// Checks for bindings (constants, statics, or let bindings) that are defined - /// with one numeric type but are consistently cast to a different type in all usages. + /// Catch casts from `0` to some pointer type /// /// ### Why is this bad? - /// If a binding is always cast to a different type when used, it would be clearer - /// and more efficient to define it with the target type from the start. + /// This generally means `null` and is better expressed as + /// {`std`, `core`}`::ptr::`{`null`, `null_mut`}. /// /// ### Example /// ```no_run - /// const SIZE: u16 = 15; - /// let arr: [u8; SIZE as usize] = [0; SIZE as usize]; + /// let a = 0 as *const u32; /// ``` /// /// Use instead: /// ```no_run - /// const SIZE: usize = 15; - /// let arr: [u8; SIZE] = [0; SIZE]; + /// let a = std::ptr::null::(); /// ``` - #[clippy::version = "1.93.0"] - pub NEEDLESS_TYPE_CAST, - nursery, - "binding defined with one type but always cast to another" -} - -pub struct Casts { - msrv: Msrv, -} - -impl Casts { - pub fn new(conf: &'static Conf) -> Self { - Self { msrv: conf.msrv } - } + #[clippy::version = "pre 1.29.0"] + pub ZERO_PTR, + style, + "using `0 as *{const, mut} T`" } impl_lint_pass!(Casts => [ @@ -887,6 +877,16 @@ impl_lint_pass!(Casts => [ ZERO_PTR, ]); +pub struct Casts { + msrv: Msrv, +} + +impl Casts { + pub fn new(conf: &'static Conf) -> Self { + Self { msrv: conf.msrv } + } +} + impl<'tcx> LateLintPass<'tcx> for Casts { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if expr.span.in_external_macro(cx.sess().source_map()) { diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 8303897d1294..5e9009c67197 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -34,6 +34,8 @@ declare_clippy_lint! { "`try_from` could replace manual bounds checking when casting" } +impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]); + pub struct CheckedConversions { msrv: Msrv, } @@ -44,8 +46,6 @@ impl CheckedConversions { } } -impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]); - impl LateLintPass<'_> for CheckedConversions { fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { if let ExprKind::Binary(op, lhs, rhs) = item.kind diff --git a/clippy_lints/src/cloned_ref_to_slice_refs.rs b/clippy_lints/src/cloned_ref_to_slice_refs.rs index 35b799aefb04..c5eabe4c2b88 100644 --- a/clippy_lints/src/cloned_ref_to_slice_refs.rs +++ b/clippy_lints/src/cloned_ref_to_slice_refs.rs @@ -44,6 +44,8 @@ declare_clippy_lint! { "cloning a reference for slice references" } +impl_lint_pass!(ClonedRefToSliceRefs<'_> => [CLONED_REF_TO_SLICE_REFS]); + pub struct ClonedRefToSliceRefs<'a> { msrv: &'a Msrv, } @@ -53,8 +55,6 @@ impl<'a> ClonedRefToSliceRefs<'a> { } } -impl_lint_pass!(ClonedRefToSliceRefs<'_> => [CLONED_REF_TO_SLICE_REFS]); - impl<'tcx> LateLintPass<'tcx> for ClonedRefToSliceRefs<'_> { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { if self.msrv.meets(cx, { diff --git a/clippy_lints/src/coerce_container_to_any.rs b/clippy_lints/src/coerce_container_to_any.rs index 2e3acb7748e2..1a7e20b98271 100644 --- a/clippy_lints/src/coerce_container_to_any.rs +++ b/clippy_lints/src/coerce_container_to_any.rs @@ -46,6 +46,7 @@ declare_clippy_lint! { nursery, "coercing to `&dyn Any` when dereferencing could produce a `dyn Any` without coercion is usually not intended" } + declare_lint_pass!(CoerceContainerToAny => [COERCE_CONTAINER_TO_ANY]); impl<'tcx> LateLintPass<'tcx> for CoerceContainerToAny { diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 950ac863d755..eaad18d25436 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -40,6 +40,8 @@ declare_clippy_lint! { @eval_always = true } +impl_lint_pass!(CognitiveComplexity => [COGNITIVE_COMPLEXITY]); + pub struct CognitiveComplexity { limit: LimitStack, } @@ -52,8 +54,6 @@ impl CognitiveComplexity { } } -impl_lint_pass!(CognitiveComplexity => [COGNITIVE_COMPLEXITY]); - impl CognitiveComplexity { fn check<'tcx>( &self, diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 0f3ef054b865..a76027caebc8 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -12,38 +12,6 @@ use rustc_session::impl_lint_pass; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, Span, Symbol}; -declare_clippy_lint! { - /// ### What it does - /// Checks for nested `if` statements which can be collapsed - /// by `&&`-combining their conditions. - /// - /// ### Why is this bad? - /// Each `if`-statement adds one level of nesting, which - /// makes code look more complex than it really is. - /// - /// ### Example - /// ```no_run - /// # let (x, y) = (true, true); - /// if x { - /// if y { - /// // … - /// } - /// } - /// ``` - /// - /// Use instead: - /// ```no_run - /// # let (x, y) = (true, true); - /// if x && y { - /// // … - /// } - /// ``` - #[clippy::version = "pre 1.29.0"] - pub COLLAPSIBLE_IF, - style, - "nested `if`s that can be collapsed (e.g., `if x { if y { ... } }`" -} - declare_clippy_lint! { /// ### What it does /// Checks for collapsible `else { if ... }` expressions @@ -80,6 +48,40 @@ declare_clippy_lint! { "nested `else`-`if` expressions that can be collapsed (e.g., `else { if x { ... } }`)" } +declare_clippy_lint! { + /// ### What it does + /// Checks for nested `if` statements which can be collapsed + /// by `&&`-combining their conditions. + /// + /// ### Why is this bad? + /// Each `if`-statement adds one level of nesting, which + /// makes code look more complex than it really is. + /// + /// ### Example + /// ```no_run + /// # let (x, y) = (true, true); + /// if x { + /// if y { + /// // … + /// } + /// } + /// ``` + /// + /// Use instead: + /// ```no_run + /// # let (x, y) = (true, true); + /// if x && y { + /// // … + /// } + /// ``` + #[clippy::version = "pre 1.29.0"] + pub COLLAPSIBLE_IF, + style, + "nested `if`s that can be collapsed (e.g., `if x { if y { ... } }`" +} + +impl_lint_pass!(CollapsibleIf => [COLLAPSIBLE_ELSE_IF, COLLAPSIBLE_IF]); + pub struct CollapsibleIf { msrv: Msrv, lint_commented_code: bool, @@ -259,8 +261,6 @@ impl CollapsibleIf { } } -impl_lint_pass!(CollapsibleIf => [COLLAPSIBLE_ELSE_IF, COLLAPSIBLE_IF]); - impl LateLintPass<'_> for CollapsibleIf { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::If(cond, then, else_) = &expr.kind diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index fd84ce70bd71..f9afdb0cabf9 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -41,6 +41,7 @@ declare_clippy_lint! { nursery, "a collection is never queried" } + declare_lint_pass!(CollectionIsNeverRead => [COLLECTION_IS_NEVER_READ]); impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead { diff --git a/clippy_lints/src/crate_in_macro_def.rs b/clippy_lints/src/crate_in_macro_def.rs index 19f62e8bf79c..509b345048c1 100644 --- a/clippy_lints/src/crate_in_macro_def.rs +++ b/clippy_lints/src/crate_in_macro_def.rs @@ -49,6 +49,7 @@ declare_clippy_lint! { suspicious, "using `crate` in a macro definition" } + declare_lint_pass!(CrateInMacroDef => [CRATE_IN_MACRO_DEF]); impl EarlyLintPass for CrateInMacroDef { diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index 45de4035d992..525f3da3efb1 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -33,6 +33,8 @@ declare_clippy_lint! { "`dbg!` macro is intended as a debugging tool" } +impl_lint_pass!(DbgMacro => [DBG_MACRO]); + pub struct DbgMacro { allow_dbg_in_tests: bool, /// Tracks the `dbg!` macro callsites that are already checked. @@ -41,8 +43,6 @@ pub struct DbgMacro { prev_ctxt: SyntaxContext, } -impl_lint_pass!(DbgMacro => [DBG_MACRO]); - impl DbgMacro { pub fn new(conf: &'static Conf) -> Self { DbgMacro { diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index a48e4d2fbd57..2064d896861b 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -69,14 +69,14 @@ declare_clippy_lint! { "binding initialized with Default should have its fields set in the initializer" } +impl_lint_pass!(Default => [DEFAULT_TRAIT_ACCESS, FIELD_REASSIGN_WITH_DEFAULT]); + #[derive(Default)] pub struct Default { // Spans linted by `field_reassign_with_default`. reassigned_linted: FxHashSet, } -impl_lint_pass!(Default => [DEFAULT_TRAIT_ACCESS, FIELD_REASSIGN_WITH_DEFAULT]); - impl<'tcx> LateLintPass<'tcx> for Default { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if !expr.span.from_expansion() diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index 95f0afcc3d88..c831f96443c6 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -45,6 +45,7 @@ declare_clippy_lint! { complexity, "unit structs can be constructed without calling `default`" } + declare_lint_pass!(DefaultConstructedUnitStructs => [ DEFAULT_CONSTRUCTED_UNIT_STRUCTS, ]); diff --git a/clippy_lints/src/default_instead_of_iter_empty.rs b/clippy_lints/src/default_instead_of_iter_empty.rs index 056e39c02af9..f041fc95fdd2 100644 --- a/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/clippy_lints/src/default_instead_of_iter_empty.rs @@ -28,6 +28,7 @@ declare_clippy_lint! { style, "check `std::iter::Empty::default()` and replace with `std::iter::empty()`" } + declare_lint_pass!(DefaultIterEmpty => [DEFAULT_INSTEAD_OF_ITER_EMPTY]); impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty { diff --git a/clippy_lints/src/default_union_representation.rs b/clippy_lints/src/default_union_representation.rs index df6525ce040e..c04e07ee7f10 100644 --- a/clippy_lints/src/default_union_representation.rs +++ b/clippy_lints/src/default_union_representation.rs @@ -48,6 +48,7 @@ declare_clippy_lint! { restriction, "unions without a `#[repr(C)]` attribute" } + declare_lint_pass!(DefaultUnionRepresentation => [DEFAULT_UNION_REPRESENTATION]); impl<'tcx> LateLintPass<'tcx> for DefaultUnionRepresentation { diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 8ad5d40b2dc7..920200bf8263 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -23,6 +23,29 @@ use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; use std::borrow::Cow; +declare_clippy_lint! { + /// ### What it does + /// Checks for dereferencing expressions which would be covered by auto-deref. + /// + /// ### Why is this bad? + /// This unnecessarily complicates the code. + /// + /// ### Example + /// ```no_run + /// let x = String::new(); + /// let y: &str = &*x; + /// ``` + /// Use instead: + /// ```no_run + /// let x = String::new(); + /// let y: &str = &x; + /// ``` + #[clippy::version = "1.64.0"] + pub EXPLICIT_AUTO_DEREF, + complexity, + "dereferencing when the compiler would automatically dereference" +} + declare_clippy_lint! { /// ### What it does /// Checks for explicit `deref()` or `deref_mut()` method calls. @@ -120,29 +143,6 @@ declare_clippy_lint! { "`ref` binding to a reference" } -declare_clippy_lint! { - /// ### What it does - /// Checks for dereferencing expressions which would be covered by auto-deref. - /// - /// ### Why is this bad? - /// This unnecessarily complicates the code. - /// - /// ### Example - /// ```no_run - /// let x = String::new(); - /// let y: &str = &*x; - /// ``` - /// Use instead: - /// ```no_run - /// let x = String::new(); - /// let y: &str = &x; - /// ``` - #[clippy::version = "1.64.0"] - pub EXPLICIT_AUTO_DEREF, - complexity, - "dereferencing when the compiler would automatically dereference" -} - impl_lint_pass!(Dereferencing<'_> => [ EXPLICIT_AUTO_DEREF, EXPLICIT_DEREF_METHODS, diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index 992ed320ce68..c04163b1c7a0 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -56,6 +56,8 @@ declare_clippy_lint! { "manual implementation of the `Default` trait which is equal to a derive" } +impl_lint_pass!(DerivableImpls => [DERIVABLE_IMPLS]); + pub struct DerivableImpls { msrv: Msrv, } @@ -66,8 +68,6 @@ impl DerivableImpls { } } -impl_lint_pass!(DerivableImpls => [DERIVABLE_IMPLS]); - fn is_path_self(e: &Expr<'_>) -> bool { if let ExprKind::Path(QPath::Resolved(_, p)) = e.kind { matches!(p.res, Res::SelfCtor(..) | Res::Def(DefKind::Ctor(..), _)) diff --git a/clippy_lints/src/derive/mod.rs b/clippy_lints/src/derive/mod.rs index a18c7533196e..fa1a7037154e 100644 --- a/clippy_lints/src/derive/mod.rs +++ b/clippy_lints/src/derive/mod.rs @@ -10,36 +10,6 @@ mod derived_hash_with_manual_eq; mod expl_impl_clone_on_copy; mod unsafe_derive_deserialize; -declare_clippy_lint! { - /// ### What it does - /// Lints against manual `PartialEq` implementations for types with a derived `Hash` - /// implementation. - /// - /// ### Why is this bad? - /// The implementation of these traits must agree (for - /// example for use with `HashMap`) so it’s probably a bad idea to use a - /// default-generated `Hash` implementation with an explicitly defined - /// `PartialEq`. In particular, the following must hold for any type: - /// - /// ```text - /// k1 == k2 ⇒ hash(k1) == hash(k2) - /// ``` - /// - /// ### Example - /// ```ignore - /// #[derive(Hash)] - /// struct Foo; - /// - /// impl PartialEq for Foo { - /// ... - /// } - /// ``` - #[clippy::version = "pre 1.29.0"] - pub DERIVED_HASH_WITH_MANUAL_EQ, - correctness, - "deriving `Hash` but implementing `PartialEq` explicitly" -} - declare_clippy_lint! { /// ### What it does /// Lints against manual `PartialOrd` and `Ord` implementations for types with a derived `Ord` @@ -91,6 +61,68 @@ declare_clippy_lint! { "deriving `Ord` but implementing `PartialOrd` explicitly" } +declare_clippy_lint! { + /// ### What it does + /// Checks for types that derive `PartialEq` and could implement `Eq`. + /// + /// ### Why is this bad? + /// If a type `T` derives `PartialEq` and all of its members implement `Eq`, + /// then `T` can always implement `Eq`. Implementing `Eq` allows `T` to be used + /// in APIs that require `Eq` types. It also allows structs containing `T` to derive + /// `Eq` themselves. + /// + /// ### Example + /// ```no_run + /// #[derive(PartialEq)] + /// struct Foo { + /// i_am_eq: i32, + /// i_am_eq_too: Vec, + /// } + /// ``` + /// Use instead: + /// ```no_run + /// #[derive(PartialEq, Eq)] + /// struct Foo { + /// i_am_eq: i32, + /// i_am_eq_too: Vec, + /// } + /// ``` + #[clippy::version = "1.63.0"] + pub DERIVE_PARTIAL_EQ_WITHOUT_EQ, + nursery, + "deriving `PartialEq` on a type that can implement `Eq`, without implementing `Eq`" +} + +declare_clippy_lint! { + /// ### What it does + /// Lints against manual `PartialEq` implementations for types with a derived `Hash` + /// implementation. + /// + /// ### Why is this bad? + /// The implementation of these traits must agree (for + /// example for use with `HashMap`) so it’s probably a bad idea to use a + /// default-generated `Hash` implementation with an explicitly defined + /// `PartialEq`. In particular, the following must hold for any type: + /// + /// ```text + /// k1 == k2 ⇒ hash(k1) == hash(k2) + /// ``` + /// + /// ### Example + /// ```ignore + /// #[derive(Hash)] + /// struct Foo; + /// + /// impl PartialEq for Foo { + /// ... + /// } + /// ``` + #[clippy::version = "pre 1.29.0"] + pub DERIVED_HASH_WITH_MANUAL_EQ, + correctness, + "deriving `Hash` but implementing `PartialEq` explicitly" +} + declare_clippy_lint! { /// ### What it does /// Checks for explicit `Clone` implementations for `Copy` @@ -152,38 +184,6 @@ declare_clippy_lint! { "deriving `serde::Deserialize` on a type that has methods using `unsafe`" } -declare_clippy_lint! { - /// ### What it does - /// Checks for types that derive `PartialEq` and could implement `Eq`. - /// - /// ### Why is this bad? - /// If a type `T` derives `PartialEq` and all of its members implement `Eq`, - /// then `T` can always implement `Eq`. Implementing `Eq` allows `T` to be used - /// in APIs that require `Eq` types. It also allows structs containing `T` to derive - /// `Eq` themselves. - /// - /// ### Example - /// ```no_run - /// #[derive(PartialEq)] - /// struct Foo { - /// i_am_eq: i32, - /// i_am_eq_too: Vec, - /// } - /// ``` - /// Use instead: - /// ```no_run - /// #[derive(PartialEq, Eq)] - /// struct Foo { - /// i_am_eq: i32, - /// i_am_eq_too: Vec, - /// } - /// ``` - #[clippy::version = "1.63.0"] - pub DERIVE_PARTIAL_EQ_WITHOUT_EQ, - nursery, - "deriving `PartialEq` on a type that can implement `Eq`, without implementing `Eq`" -} - declare_lint_pass!(Derive => [ DERIVED_HASH_WITH_MANUAL_EQ, DERIVE_ORD_XOR_PARTIAL_ORD, diff --git a/clippy_lints/src/disallowed_fields.rs b/clippy_lints/src/disallowed_fields.rs index f1136556e2ed..9873c32f427f 100644 --- a/clippy_lints/src/disallowed_fields.rs +++ b/clippy_lints/src/disallowed_fields.rs @@ -56,6 +56,8 @@ declare_clippy_lint! { "declaration of a disallowed field use" } +impl_lint_pass!(DisallowedFields => [DISALLOWED_FIELDS]); + pub struct DisallowedFields { disallowed: DefIdMap<(&'static str, &'static DisallowedPath)>, } @@ -74,8 +76,6 @@ impl DisallowedFields { } } -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 { diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs index 1c9c971730f6..7253b65e4337 100644 --- a/clippy_lints/src/disallowed_macros.rs +++ b/clippy_lints/src/disallowed_macros.rs @@ -63,6 +63,8 @@ declare_clippy_lint! { "use of a disallowed macro" } +impl_lint_pass!(DisallowedMacros => [DISALLOWED_MACROS]); + pub struct DisallowedMacros { disallowed: DefIdMap<(&'static str, &'static DisallowedPath)>, seen: FxHashSet, @@ -125,8 +127,6 @@ impl DisallowedMacros { } } -impl_lint_pass!(DisallowedMacros => [DISALLOWED_MACROS]); - impl LateLintPass<'_> for DisallowedMacros { fn check_crate(&mut self, cx: &LateContext<'_>) { // once we check a crate in the late pass we can emit the early pass lints diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs index 58403ad19235..e2fd71b7d990 100644 --- a/clippy_lints/src/disallowed_methods.rs +++ b/clippy_lints/src/disallowed_methods.rs @@ -61,6 +61,8 @@ declare_clippy_lint! { "use of a disallowed method call" } +impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]); + pub struct DisallowedMethods { disallowed: DefIdMap<(&'static str, &'static DisallowedPath)>, } @@ -84,8 +86,6 @@ impl DisallowedMethods { } } -impl_lint_pass!(DisallowedMethods => [DISALLOWED_METHODS]); - impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if expr.span.desugaring_kind().is_some() { diff --git a/clippy_lints/src/disallowed_names.rs b/clippy_lints/src/disallowed_names.rs index 566aa12b08f5..1f658b2aa068 100644 --- a/clippy_lints/src/disallowed_names.rs +++ b/clippy_lints/src/disallowed_names.rs @@ -26,6 +26,8 @@ declare_clippy_lint! { "usage of a disallowed/placeholder name" } +impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]); + pub struct DisallowedNames { disallow: FxHashSet, } @@ -38,8 +40,6 @@ impl DisallowedNames { } } -impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]); - impl<'tcx> LateLintPass<'tcx> for DisallowedNames { fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { if let PatKind::Binding(.., ident, _) = pat.kind diff --git a/clippy_lints/src/disallowed_script_idents.rs b/clippy_lints/src/disallowed_script_idents.rs index 5b4fe2a6b803..4596d9457c0b 100644 --- a/clippy_lints/src/disallowed_script_idents.rs +++ b/clippy_lints/src/disallowed_script_idents.rs @@ -45,6 +45,8 @@ declare_clippy_lint! { "usage of non-allowed Unicode scripts" } +impl_lint_pass!(DisallowedScriptIdents => [DISALLOWED_SCRIPT_IDENTS]); + pub struct DisallowedScriptIdents { whitelist: FxHashSet