From 9b02ff9012190e34401a26adf7022a3484c10537 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sun, 28 Sep 2025 14:56:23 +0000 Subject: [PATCH] Create new lints with `#[clippy::version = "nightly"]` --- book/src/development/adding_lints.md | 10 +- book/src/development/defining_lints.md | 4 +- .../infrastructure/changelog_update.md | 9 +- clippy_dev/src/deprecate_lint.rs | 6 +- clippy_dev/src/main.rs | 11 +- clippy_dev/src/new_lint.rs | 31 ++---- clippy_dev/src/rename_lint.rs | 7 +- clippy_dev/src/update_lints.rs | 49 +++----- clippy_lints/src/deprecated_lints.rs | 105 ++++-------------- clippy_lints/src/lib.rs | 3 +- .../src/lint_without_lint_pass.rs | 3 +- tests/compile-test.rs | 17 ++- tests/lint-definitions.rs | 35 ++++++ ...nvention.rs => lint-message-convention.rs} | 0 .../check_clippy_version_attribute.rs | 9 ++ .../check_clippy_version_attribute.stderr | 8 +- util/gh-pages/script.js | 11 +- 17 files changed, 132 insertions(+), 186 deletions(-) create mode 100644 tests/lint-definitions.rs rename tests/{lint_message_convention.rs => lint-message-convention.rs} (100%) diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index 2b89e94cf8f4..dca2c0fa6474 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -233,7 +233,7 @@ declare_clippy_lint! { /// ```rust /// // example code /// ``` - #[clippy::version = "1.29.0"] + #[clippy::version = "nightly"] pub FOO_FUNCTIONS, pedantic, "function named `foo`, which is not a descriptive name" @@ -245,10 +245,8 @@ declare_clippy_lint! { this][example_lint_page]. To render and open this documentation locally in a browser, run `cargo dev serve`. * The `#[clippy::version]` attribute will be rendered as part of the lint - documentation. The value should be set to the current Rust version that the - lint is developed in, it can be retrieved by running `rustc -vV` in the - rust-clippy directory. The version is listed under *release*. (Use the version - without the `-nightly`) suffix. + documentation. The value of `"nightly"` will be replaced automatically + as part of the release process after the lint is merged. * `FOO_FUNCTIONS` is the name of our lint. Be sure to follow the [lint naming guidelines][lint_naming] here when naming your lint. In short, the name should state the thing that is being checked for and read well when used with @@ -587,7 +585,7 @@ declare_clippy_lint! { /// ```rust,ignore /// // A short example of improved code that doesn't trigger the lint /// ``` - #[clippy::version = "1.29.0"] + #[clippy::version = "nightly"] pub FOO_FUNCTIONS, pedantic, "function named `foo`, which is not a descriptive name" diff --git a/book/src/development/defining_lints.md b/book/src/development/defining_lints.md index cb6d7b740dbd..a48e834c9893 100644 --- a/book/src/development/defining_lints.md +++ b/book/src/development/defining_lints.md @@ -168,10 +168,10 @@ declare_clippy_lint! { /// ```rust /// // example code which does not raise Clippy warning /// ``` - #[clippy::version = "1.70.0"] // <- In which version was this implemented, keep it up to date! + #[clippy::version = "nightly"] pub LINT_NAME, // <- The lint name IN_ALL_CAPS pedantic, // <- The lint group - "default lint description" // <- A lint description, e.g. "A function has an unit return type." + "default lint description" // <- A lint description, e.g. "function with the unit return type" } ``` diff --git a/book/src/development/infrastructure/changelog_update.md b/book/src/development/infrastructure/changelog_update.md index c96ff228b01a..9c9e7b0da368 100644 --- a/book/src/development/infrastructure/changelog_update.md +++ b/book/src/development/infrastructure/changelog_update.md @@ -98,8 +98,10 @@ that label in the changelog. If you can, remove the `beta-accepted` labels ### 5. Update `clippy::version` attributes -Next, make sure to check that the `#[clippy::version]` attributes for the added -lints contain the correct version. +Next, make sure to check that the `#[clippy::version]` attributes for the newly +added and deprecated lints contain the version of the release you're writing the +changelog for. + In order to find lints that need a version update, go through the lints in the "New Lints" section and run the following command for each lint name: @@ -110,6 +112,9 @@ grep -rB1 "pub $LINT_NAME" . The version shown should match the version of the release the changelog is written for. If not, update the version to the changelog version. +Newly created lints will have `#[clippy::version = "nightly"]` and be handled +during the sync, but many existing PRs will still have an incorrect version. + [changelog]: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md [forge]: https://forge.rust-lang.org/ [rust_master_tools]: https://github.com/rust-lang/rust/tree/master/src/tools/clippy diff --git a/clippy_dev/src/deprecate_lint.rs b/clippy_dev/src/deprecate_lint.rs index 3bdc5b277232..fa922dcdb499 100644 --- a/clippy_dev/src/deprecate_lint.rs +++ b/clippy_dev/src/deprecate_lint.rs @@ -1,5 +1,5 @@ use crate::update_lints::{DeprecatedLint, Lint, find_lint_decls, generate_lint_files, read_deprecated_lints}; -use crate::utils::{UpdateMode, Version}; +use crate::utils::UpdateMode; use std::ffi::OsStr; use std::path::{Path, PathBuf}; use std::{fs, io}; @@ -13,7 +13,7 @@ use std::{fs, io}; /// # Panics /// /// If a file path could not read from or written to -pub fn deprecate(clippy_version: Version, name: &str, reason: &str) { +pub fn deprecate(name: &str, reason: &str) { if let Some((prefix, _)) = name.split_once("::") { panic!("`{name}` should not contain the `{prefix}` prefix"); } @@ -37,7 +37,7 @@ pub fn deprecate(clippy_version: Version, name: &str, reason: &str) { DeprecatedLint { name: prefixed_name, reason: reason.into(), - version: clippy_version.rust_display().to_string(), + version: "nightly".to_string(), }, ), } diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 5fef231f6ca1..8e9da763d230 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -35,7 +35,7 @@ fn main() { category, r#type, msrv, - } => match new_lint::create(clippy.version, pass, &name, &category, r#type.as_deref(), msrv) { + } => match new_lint::create(pass, &name, &category, r#type.as_deref(), msrv) { Ok(()) => update_lints::update(UpdateMode::Change), Err(e) => eprintln!("Unable to create lint: {e}"), }, @@ -79,13 +79,8 @@ fn main() { old_name, new_name, uplift, - } => rename_lint::rename( - clippy.version, - &old_name, - new_name.as_ref().unwrap_or(&old_name), - uplift, - ), - DevCommand::Deprecate { name, reason } => deprecate_lint::deprecate(clippy.version, &name, &reason), + } => rename_lint::rename(&old_name, new_name.as_ref().unwrap_or(&old_name), uplift), + DevCommand::Deprecate { name, reason } => deprecate_lint::deprecate(&name, &reason), DevCommand::Sync(SyncCommand { subcommand }) => match subcommand { SyncSubcommand::UpdateNightly => sync::update_nightly(), }, diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 4121daa85e6d..39b23b0eb815 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -1,4 +1,4 @@ -use crate::utils::{RustSearcher, Token, Version}; +use crate::utils::{RustSearcher, Token}; use clap::ValueEnum; use indoc::{formatdoc, writedoc}; use std::fmt::{self, Write as _}; @@ -22,7 +22,6 @@ impl fmt::Display for Pass { } struct LintData<'a> { - clippy_version: Version, pass: Pass, name: &'a str, category: &'a str, @@ -50,21 +49,13 @@ impl Context for io::Result { /// # Errors /// /// This function errors out if the files couldn't be created or written to. -pub fn create( - clippy_version: Version, - pass: Pass, - name: &str, - category: &str, - mut ty: Option<&str>, - msrv: bool, -) -> io::Result<()> { +pub fn create(pass: Pass, name: &str, category: &str, mut ty: Option<&str>, msrv: bool) -> io::Result<()> { if category == "cargo" && ty.is_none() { // `cargo` is a special category, these lints should always be in `clippy_lints/src/cargo` ty = Some("cargo"); } let lint = LintData { - clippy_version, pass, name, category, @@ -293,11 +284,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { ); } - let _: fmt::Result = writeln!( - result, - "{}", - get_lint_declaration(lint.clippy_version, &name_upper, category) - ); + let _: fmt::Result = writeln!(result, "{}", get_lint_declaration(&name_upper, category)); if enable_msrv { let _: fmt::Result = writedoc!( @@ -335,7 +322,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { result } -fn get_lint_declaration(version: Version, name_upper: &str, category: &str) -> String { +fn get_lint_declaration(name_upper: &str, category: &str) -> String { let justification_heading = if category == "restriction" { "Why restrict this?" } else { @@ -356,12 +343,11 @@ fn get_lint_declaration(version: Version, name_upper: &str, category: &str) -> S /// ```no_run /// // example code which does not raise clippy warning /// ``` - #[clippy::version = "{}"] + #[clippy::version = "nightly"] pub {name_upper}, {category}, "default lint description" - }}"#, - version.rust_display(), + }}"# ) } @@ -460,10 +446,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> // Add the lint declaration to `mod.rs` file_contents.insert_str( lint_decl_end, - &format!( - "\n\n{}", - get_lint_declaration(lint.clippy_version, &lint_name_upper, lint.category) - ), + &format!("\n\n{}", get_lint_declaration(&lint_name_upper, lint.category)), ); // Add the lint to `impl_lint_pass`/`declare_lint_pass` diff --git a/clippy_dev/src/rename_lint.rs b/clippy_dev/src/rename_lint.rs index d62597428e21..8e11306531cc 100644 --- a/clippy_dev/src/rename_lint.rs +++ b/clippy_dev/src/rename_lint.rs @@ -1,7 +1,7 @@ use crate::update_lints::{RenamedLint, find_lint_decls, generate_lint_files, read_deprecated_lints}; use crate::utils::{ - ErrAction, FileUpdater, RustSearcher, Token, 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, + ErrAction, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, delete_dir_if_exists, delete_file_if_exists, + expect_action, try_rename_dir, try_rename_file, walk_dir_no_dot_or_target, }; use rustc_lexer::TokenKind; use std::ffi::OsString; @@ -24,7 +24,7 @@ use std::path::Path; /// * If `old_name` doesn't name an existing lint. /// * If `old_name` names a deprecated or renamed lint. #[expect(clippy::too_many_lines)] -pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: bool) { +pub fn rename(old_name: &str, new_name: &str, uplift: bool) { if let Some((prefix, _)) = old_name.split_once("::") { panic!("`{old_name}` should not contain the `{prefix}` prefix"); } @@ -68,7 +68,6 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b } else { String::from_iter(["clippy::", new_name]) }, - version: clippy_version.rust_display().to_string(), }, ); }, diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 5f6e874ffe25..3c0ad1a9aeb7 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -81,12 +81,11 @@ pub fn generate_lint_files( &mut |_, src, dst| { let mut searcher = RustSearcher::new(src); assert!( - searcher.find_token(Token::Ident("declare_with_version")) - && searcher.find_token(Token::Ident("declare_with_version")), + searcher.find_token(Token::Ident("deprecated")) && searcher.find_token(Token::Ident("deprecated")), "error reading deprecated lints" ); dst.push_str(&src[..searcher.pos() as usize]); - dst.push_str("! { DEPRECATED(DEPRECATED_VERSION) = [\n"); + dst.push_str("![\n"); for lint in deprecated { write!( dst, @@ -96,20 +95,15 @@ pub fn generate_lint_files( .unwrap(); } dst.push_str( - "]}\n\n\ + "];\n\n\ #[rustfmt::skip]\n\ - declare_with_version! { RENAMED(RENAMED_VERSION) = [\n\ + pub const RENAMED: &[(&str, &str)] = &[\n\ ", ); for lint in renamed { - write!( - dst, - " #[clippy::version = \"{}\"]\n (\"{}\", \"{}\"),\n", - lint.version, lint.old_name, lint.new_name, - ) - .unwrap(); + writeln!(dst, " (\"{}\", \"{}\"),", lint.old_name, lint.new_name).unwrap(); } - dst.push_str("]}\n"); + dst.push_str("];\n"); UpdateStatus::from_changed(src != dst) }, ); @@ -220,7 +214,6 @@ pub struct DeprecatedLint { pub struct RenamedLint { pub old_name: String, pub new_name: String, - pub version: String, } /// Finds all lint declarations (`declare_clippy_lint!`) @@ -318,21 +311,14 @@ pub fn read_deprecated_lints() -> (Vec, Vec) { #[allow(clippy::enum_glob_use)] use Token::*; #[rustfmt::skip] - static DECL_TOKENS: &[Token<'_>] = &[ + static VERSION_TOKENS: &[Token<'_>] = &[ // #[clippy::version = "version"] Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, CaptureLitStr, CloseBracket, - // ("first", "second"), - OpenParen, CaptureLitStr, Comma, CaptureLitStr, CloseParen, Comma, - ]; - #[rustfmt::skip] - static DEPRECATED_TOKENS: &[Token<'_>] = &[ - // !{ DEPRECATED(DEPRECATED_VERSION) = [ - Bang, OpenBrace, Ident("DEPRECATED"), OpenParen, Ident("DEPRECATED_VERSION"), CloseParen, Eq, OpenBracket, ]; #[rustfmt::skip] - static RENAMED_TOKENS: &[Token<'_>] = &[ - // !{ RENAMED(RENAMED_VERSION) = [ - Bang, OpenBrace, Ident("RENAMED"), OpenParen, Ident("RENAMED_VERSION"), CloseParen, Eq, OpenBracket, + static DECL_TOKENS: &[Token<'_>] = &[ + // ("first", "second"), + OpenParen, CaptureLitStr, Comma, CaptureLitStr, CloseParen, Comma, ]; let path = "clippy_lints/src/deprecated_lints.rs"; @@ -345,15 +331,16 @@ pub fn read_deprecated_lints() -> (Vec, Vec) { // First instance is the macro definition. assert!( - searcher.find_token(Ident("declare_with_version")), + searcher.find_token(Ident("deprecated")), "error reading deprecated lints" ); - if searcher.find_token(Ident("declare_with_version")) && searcher.match_tokens(DEPRECATED_TOKENS, &mut []) { + if searcher.find_token(Ident("deprecated")) && searcher.match_tokens(&[Bang, OpenBracket], &mut []) { let mut version = ""; let mut name = ""; let mut reason = ""; - while searcher.match_tokens(DECL_TOKENS, &mut [&mut version, &mut name, &mut reason]) { + while searcher.match_tokens(VERSION_TOKENS, &mut [&mut version]) { + assert!(searcher.match_tokens(DECL_TOKENS, &mut [&mut name, &mut reason])); deprecated.push(DeprecatedLint { name: parse_str_single_line(path.as_ref(), name), reason: parse_str_single_line(path.as_ref(), reason), @@ -364,15 +351,15 @@ pub fn read_deprecated_lints() -> (Vec, Vec) { panic!("error reading deprecated lints"); } - if searcher.find_token(Ident("declare_with_version")) && searcher.match_tokens(RENAMED_TOKENS, &mut []) { - let mut version = ""; + // pub const RENAMED: &[(&str, &str)] = &[ + // ^^^^^^^ ^ ^ + if searcher.find_token(Ident("RENAMED")) && searcher.find_token(Eq) && searcher.find_token(OpenBracket) { let mut old_name = ""; let mut new_name = ""; - while searcher.match_tokens(DECL_TOKENS, &mut [&mut version, &mut old_name, &mut new_name]) { + while searcher.match_tokens(DECL_TOKENS, &mut [&mut old_name, &mut new_name]) { renamed.push(RenamedLint { old_name: parse_str_single_line(path.as_ref(), old_name), new_name: parse_str_single_line(path.as_ref(), new_name), - version: parse_str_single_line(path.as_ref(), version), }); } } else { diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index 80b74f50223a..55b2e8788bfd 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -1,19 +1,28 @@ // This file is managed by `cargo dev rename_lint` and `cargo dev deprecate_lint`. // Prefer to use those when possible. -macro_rules! declare_with_version { - ($name:ident($name_version:ident) = [$( +#[derive(Copy, Clone, Debug)] +pub struct Deprecation { + pub name: &'static str, + pub reason: &'static str, + pub version: &'static str, +} + +macro_rules! deprecated { + ($( #[clippy::version = $version:literal] - $e:expr, - )*]) => { - pub static $name: &[(&str, &str)] = &[$($e),*]; - #[allow(unused)] - pub static $name_version: &[&str] = &[$($version),*]; + ($name:literal, $reason:literal), + )*) => { + &[$(Deprecation { + name: $name, + reason: $reason, + version: $version, + }),*] }; } #[rustfmt::skip] -declare_with_version! { DEPRECATED(DEPRECATED_VERSION) = [ +pub const DEPRECATED: &[Deprecation] = deprecated![ #[clippy::version = "1.30.0"] ("clippy::assign_ops", "compound operators are harmless and linting on them is not in scope for clippy"), #[clippy::version = "pre 1.29.0"] @@ -46,156 +55,82 @@ declare_with_version! { DEPRECATED(DEPRECATED_VERSION) = [ ("clippy::unused_collect", "`Iterator::collect` is now marked as `#[must_use]`"), #[clippy::version = "1.54.0"] ("clippy::wrong_pub_self_convention", "`clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config"), -]} +]; #[rustfmt::skip] -declare_with_version! { RENAMED(RENAMED_VERSION) = [ - #[clippy::version = ""] +pub const RENAMED: &[(&str, &str)] = &[ ("clippy::almost_complete_letter_range", "clippy::almost_complete_range"), - #[clippy::version = ""] ("clippy::blacklisted_name", "clippy::disallowed_names"), - #[clippy::version = ""] ("clippy::block_in_if_condition_expr", "clippy::blocks_in_conditions"), - #[clippy::version = ""] ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_conditions"), - #[clippy::version = ""] ("clippy::blocks_in_if_conditions", "clippy::blocks_in_conditions"), - #[clippy::version = ""] ("clippy::box_vec", "clippy::box_collection"), - #[clippy::version = ""] ("clippy::cast_ref_to_mut", "invalid_reference_casting"), - #[clippy::version = ""] ("clippy::clone_double_ref", "suspicious_double_ref_op"), - #[clippy::version = ""] ("clippy::cmp_nan", "invalid_nan_comparisons"), - #[clippy::version = ""] ("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"), - #[clippy::version = ""] ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"), - #[clippy::version = ""] ("clippy::derive_hash_xor_eq", "clippy::derived_hash_with_manual_eq"), - #[clippy::version = ""] ("clippy::disallowed_method", "clippy::disallowed_methods"), - #[clippy::version = ""] ("clippy::disallowed_type", "clippy::disallowed_types"), - #[clippy::version = "1.86.0"] ("clippy::double_neg", "double_negations"), - #[clippy::version = ""] ("clippy::drop_bounds", "drop_bounds"), - #[clippy::version = ""] ("clippy::drop_copy", "dropping_copy_types"), - #[clippy::version = ""] ("clippy::drop_ref", "dropping_references"), - #[clippy::version = ""] ("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"), - #[clippy::version = "1.53.0"] ("clippy::filter_map", "clippy::manual_filter_map"), - #[clippy::version = "1.51.0"] ("clippy::find_map", "clippy::manual_find_map"), - #[clippy::version = ""] ("clippy::fn_address_comparisons", "unpredictable_function_pointer_comparisons"), - #[clippy::version = ""] ("clippy::fn_null_check", "useless_ptr_null_checks"), - #[clippy::version = ""] ("clippy::for_loop_over_option", "for_loops_over_fallibles"), - #[clippy::version = ""] ("clippy::for_loop_over_result", "for_loops_over_fallibles"), - #[clippy::version = ""] ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"), - #[clippy::version = ""] ("clippy::forget_copy", "forgetting_copy_types"), - #[clippy::version = ""] ("clippy::forget_ref", "forgetting_references"), - #[clippy::version = ""] ("clippy::identity_conversion", "clippy::useless_conversion"), - #[clippy::version = "pre 1.29.0"] ("clippy::if_let_redundant_pattern_matching", "clippy::redundant_pattern_matching"), - #[clippy::version = ""] ("clippy::if_let_some_result", "clippy::match_result_ok"), - #[clippy::version = ""] ("clippy::incorrect_clone_impl_on_copy_type", "clippy::non_canonical_clone_impl"), - #[clippy::version = ""] ("clippy::incorrect_partial_ord_impl_on_ord_type", "clippy::non_canonical_partial_ord_impl"), - #[clippy::version = ""] ("clippy::integer_arithmetic", "clippy::arithmetic_side_effects"), - #[clippy::version = ""] ("clippy::into_iter_on_array", "array_into_iter"), - #[clippy::version = ""] ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"), - #[clippy::version = "CURRENT_RUSTC_VERSION"] ("clippy::invalid_null_ptr_usage", "invalid_null_arguments"), - #[clippy::version = ""] ("clippy::invalid_ref", "invalid_value"), - #[clippy::version = ""] ("clippy::invalid_utf8_in_unchecked", "invalid_from_utf8_unchecked"), - #[clippy::version = ""] ("clippy::let_underscore_drop", "let_underscore_drop"), - #[clippy::version = ""] ("clippy::logic_bug", "clippy::overly_complex_bool_expr"), - #[clippy::version = "1.80.0"] ("clippy::maybe_misused_cfg", "unexpected_cfgs"), - #[clippy::version = ""] ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"), - #[clippy::version = "1.80.0"] ("clippy::mismatched_target_os", "unexpected_cfgs"), - #[clippy::version = ""] ("clippy::new_without_default_derive", "clippy::new_without_default"), - #[clippy::version = ""] ("clippy::option_and_then_some", "clippy::bind_instead_of_map"), - #[clippy::version = ""] ("clippy::option_expect_used", "clippy::expect_used"), - #[clippy::version = ""] ("clippy::option_map_unwrap_or", "clippy::map_unwrap_or"), - #[clippy::version = ""] ("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or"), - #[clippy::version = ""] ("clippy::option_unwrap_used", "clippy::unwrap_used"), - #[clippy::version = ""] ("clippy::overflow_check_conditional", "clippy::panicking_overflow_checks"), - #[clippy::version = ""] ("clippy::panic_params", "non_fmt_panics"), - #[clippy::version = ""] ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"), - #[clippy::version = ""] ("clippy::ref_in_deref", "clippy::needless_borrow"), - #[clippy::version = ""] ("clippy::result_expect_used", "clippy::expect_used"), - #[clippy::version = ""] ("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or"), - #[clippy::version = ""] ("clippy::result_unwrap_used", "clippy::unwrap_used"), - #[clippy::version = ""] ("clippy::reverse_range_loop", "clippy::reversed_empty_ranges"), - #[clippy::version = ""] ("clippy::single_char_push_str", "clippy::single_char_add_str"), - #[clippy::version = ""] ("clippy::stutter", "clippy::module_name_repetitions"), - #[clippy::version = ""] ("clippy::temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"), - #[clippy::version = ""] ("clippy::thread_local_initializer_can_be_made_const", "clippy::missing_const_for_thread_local"), - #[clippy::version = ""] ("clippy::to_string_in_display", "clippy::recursive_format_impl"), - #[clippy::version = "1.88.0"] ("clippy::transmute_float_to_int", "unnecessary_transmutes"), - #[clippy::version = "1.88.0"] ("clippy::transmute_int_to_char", "unnecessary_transmutes"), - #[clippy::version = "1.88.0"] ("clippy::transmute_int_to_float", "unnecessary_transmutes"), - #[clippy::version = "1.88.0"] ("clippy::transmute_num_to_bytes", "unnecessary_transmutes"), - #[clippy::version = "1.90.0"] ("clippy::unchecked_duration_subtraction", "clippy::unchecked_time_subtraction"), - #[clippy::version = ""] ("clippy::undropped_manually_drops", "undropped_manually_drops"), - #[clippy::version = ""] ("clippy::unknown_clippy_lints", "unknown_lints"), - #[clippy::version = ""] ("clippy::unused_label", "unused_labels"), - #[clippy::version = ""] ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"), - #[clippy::version = ""] ("clippy::vtable_address_comparisons", "ambiguous_wide_pointer_comparisons"), - #[clippy::version = ""] ("clippy::zero_width_space", "clippy::invisible_characters"), -]} +]; diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 51dabee78e9f..a9a043a2452b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -410,6 +410,7 @@ mod zombie_processes; use clippy_config::{Conf, get_configuration_metadata, sanitize_explanation}; use clippy_utils::macros::FormatArgsStorage; +use deprecated_lints::Deprecation; use rustc_data_structures::fx::FxHashSet; use rustc_lint::Lint; use utils::attr_collector::{AttrCollector, AttrStorage}; @@ -444,7 +445,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co for (old_name, new_name) in deprecated_lints::RENAMED { store.register_renamed(old_name, new_name); } - for (name, reason) in deprecated_lints::DEPRECATED { + for Deprecation { name, reason, .. } in deprecated_lints::DEPRECATED { store.register_removed(name, reason); } diff --git a/clippy_lints_internal/src/lint_without_lint_pass.rs b/clippy_lints_internal/src/lint_without_lint_pass.rs index fda65bc84eda..cd7327b35e7e 100644 --- a/clippy_lints_internal/src/lint_without_lint_pass.rs +++ b/clippy_lints_internal/src/lint_without_lint_pass.rs @@ -74,6 +74,7 @@ declare_tool_lint! { /// /// Valid values are: /// * "pre 1.29.0" + /// * "nightly" /// * any valid semantic version pub clippy::INVALID_CLIPPY_VERSION_ATTRIBUTE, Warn, @@ -216,7 +217,7 @@ pub(super) fn is_lint_ref_type(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<'_>) { if let Some(value) = extract_clippy_version_value(cx, item) { - if value.as_str() == "pre 1.29.0" { + if matches!(value.as_str(), "pre 1.29.0" | "nightly") { return; } diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 6b6dfd7b81ea..1ea9974a0b52 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -8,7 +8,7 @@ use cargo_metadata::Message; use cargo_metadata::diagnostic::{Applicability, Diagnostic}; use clippy_config::ClippyConfiguration; use clippy_lints::declared_lints::LINTS; -use clippy_lints::deprecated_lints::{DEPRECATED, DEPRECATED_VERSION, RENAMED}; +use clippy_lints::deprecated_lints::{DEPRECATED, Deprecation, RENAMED}; use declare_clippy_lint::LintInfo; use pulldown_cmark::{Options, Parser, html}; use serde::Deserialize; @@ -27,7 +27,7 @@ use std::ffi::{OsStr, OsString}; use std::fmt::Write; use std::path::{Path, PathBuf}; use std::sync::mpsc::{Sender, channel}; -use std::{fs, iter, thread}; +use std::{fs, thread}; mod test_utils; @@ -503,10 +503,7 @@ impl DiagnosticCollector { let mut metadata: Vec = LINTS .iter() .map(|lint| LintMetadata::new(lint, &applicabilities, &configs)) - .chain( - iter::zip(DEPRECATED, DEPRECATED_VERSION) - .map(|((lint, reason), version)| LintMetadata::new_deprecated(lint, reason, version)), - ) + .chain(DEPRECATED.iter().copied().map(LintMetadata::new_deprecated)) .collect(); metadata.sort_unstable_by(|a, b| a.id.cmp(&b.id)); @@ -610,15 +607,15 @@ impl LintMetadata { } } - fn new_deprecated(name: &str, reason: &str, version: &'static str) -> Self { + fn new_deprecated(deprecated: Deprecation) -> Self { // The reason starts with a lowercase letter and ends without a period. // This needs to be fixed for the website. - let mut reason = reason.to_owned(); + let mut reason = deprecated.reason.to_owned(); if let Some(reason) = reason.get_mut(0..1) { reason.make_ascii_uppercase(); } Self { - id: name.strip_prefix("clippy::").unwrap().into(), + id: deprecated.name.strip_prefix("clippy::").unwrap().into(), id_location: None, group: "deprecated", level: "none", @@ -627,7 +624,7 @@ impl LintMetadata { Nothing. This lint has been deprecated\n\n\ ### Deprecation reason\n\n{reason}.\n", ), - version, + version: deprecated.version, applicability: Applicability::Unspecified, } } diff --git a/tests/lint-definitions.rs b/tests/lint-definitions.rs new file mode 100644 index 000000000000..3608d72ca501 --- /dev/null +++ b/tests/lint-definitions.rs @@ -0,0 +1,35 @@ +#![feature(rustc_private)] + +use clippy_lints::declared_lints::LINTS; +use clippy_lints::deprecated_lints::DEPRECATED; +use test_utils::IS_RUSTC_TEST_SUITE; + +mod test_utils; + +#[test] +fn no_nightly_versions_in_rust_repo() { + if !IS_RUSTC_TEST_SUITE { + return; + } + + let mut failed = false; + + for lint in LINTS { + if lint.version == "nightly" { + let name = lint.name_lower(); + let location = lint.location.replace("#L", ":"); + println!(r#"{location}: {name} has #[clippy::version = "nightly"]"#); + failed = true; + } + } + + for deprecation in DEPRECATED { + if deprecation.version == "nightly" { + let name = deprecation.name.strip_prefix("clippy::").unwrap(); + println!(r#"clippy_lints/src/deprecated_lints.rs: {name} has #[clippy::version = "nightly"]"#); + failed = true; + } + } + + assert!(!failed); +} diff --git a/tests/lint_message_convention.rs b/tests/lint-message-convention.rs similarity index 100% rename from tests/lint_message_convention.rs rename to tests/lint-message-convention.rs diff --git a/tests/ui-internal/check_clippy_version_attribute.rs b/tests/ui-internal/check_clippy_version_attribute.rs index 897002949e67..36c3f5b8c5dc 100644 --- a/tests/ui-internal/check_clippy_version_attribute.rs +++ b/tests/ui-internal/check_clippy_version_attribute.rs @@ -34,6 +34,14 @@ declare_tool_lint! { report_in_external_macro: true } +declare_tool_lint! { + #[clippy::version = "nightly"] + pub clippy::VALID_NIGHTLY, + Warn, + "Three", + report_in_external_macro: true +} + /////////////////////// // Invalid attributes /////////////////////// @@ -90,6 +98,7 @@ declare_lint_pass!(Pass2 => [ VALID_ONE, VALID_TWO, VALID_THREE, + VALID_NIGHTLY, INVALID_ONE, INVALID_TWO, MISSING_ATTRIBUTE_ONE, diff --git a/tests/ui-internal/check_clippy_version_attribute.stderr b/tests/ui-internal/check_clippy_version_attribute.stderr index 952bc9440303..4ebd282f0b16 100644 --- a/tests/ui-internal/check_clippy_version_attribute.stderr +++ b/tests/ui-internal/check_clippy_version_attribute.stderr @@ -1,5 +1,5 @@ error: this item has an invalid `clippy::version` attribute - --> tests/ui-internal/check_clippy_version_attribute.rs:40:1 + --> tests/ui-internal/check_clippy_version_attribute.rs:48:1 | LL | / declare_tool_lint! { LL | | @@ -19,7 +19,7 @@ LL | #![deny(clippy::invalid_clippy_version_attribute, clippy::missing_clippy_ve = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: this item has an invalid `clippy::version` attribute - --> tests/ui-internal/check_clippy_version_attribute.rs:49:1 + --> tests/ui-internal/check_clippy_version_attribute.rs:57:1 | LL | / declare_tool_lint! { LL | | @@ -34,7 +34,7 @@ LL | | } = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: this lint is missing the `clippy::version` attribute or version value - --> tests/ui-internal/check_clippy_version_attribute.rs:61:1 + --> tests/ui-internal/check_clippy_version_attribute.rs:69:1 | LL | / declare_tool_lint! { LL | | @@ -54,7 +54,7 @@ LL | #![deny(clippy::invalid_clippy_version_attribute, clippy::missing_clippy_ve = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: this lint is missing the `clippy::version` attribute or version value - --> tests/ui-internal/check_clippy_version_attribute.rs:70:1 + --> tests/ui-internal/check_clippy_version_attribute.rs:78:1 | LL | / declare_tool_lint! { LL | | diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js index 2b6ee67c37dc..d0e602a0a7d4 100644 --- a/util/gh-pages/script.js +++ b/util/gh-pages/script.js @@ -243,16 +243,17 @@ window.filters = { filters.allLints = Array.prototype.slice.call( document.getElementsByTagName("article"), ).map(elem => { - let version = elem.querySelector(".label-version").innerText; + let versionText = elem.querySelector(".label-version").innerText; // Strip the "pre " prefix for pre 1.29.0 lints - if (version.startsWith("pre ")) { - version = version.slice(4); + if (versionText.startsWith("pre ")) { + versionText = versionText.slice(4); } + const version = versionText == "nightly" ? Infinity : Number(versionText.split(".")[1]); return { - elem: elem, + elem, group: elem.querySelector(".lint-group").innerText, level: elem.querySelector(".lint-level").innerText, - version: parseInt(version.split(".")[1]), + version, applicability: elem.querySelector(".applicability").innerText, filteredOut: false, searchFilteredOut: false,