From 5aeb08ed70b4bb40696f4c0d3216c749b7175a25 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 5 Oct 2024 02:23:59 +0200 Subject: [PATCH] add a book page for lint subgroups --- book/src/SUMMARY.md | 1 + book/src/lint_subgroups.md | 218 +++++++++++++++++ clippy_dev/src/lib.rs | 2 +- clippy_dev/src/update_lints.rs | 221 +++++++++++++++--- clippy_lints/src/assigning_clones.rs | 3 +- clippy_lints/src/dbg_macro.rs | 3 +- clippy_lints/src/declare_clippy_lint.rs | 15 +- clippy_lints/src/format_push_string.rs | 3 +- clippy_lints/src/indexing_slicing.rs | 3 +- clippy_lints/src/methods/mod.rs | 24 +- .../src/missing_asserts_for_indexing.rs | 3 +- clippy_lints/src/mutex_atomic.rs | 3 +- clippy_lints/src/operators/mod.rs | 6 +- clippy_lints/src/panic_unimplemented.rs | 12 +- clippy_lints/src/pass_by_ref_or_value.rs | 3 +- clippy_lints/src/redundant_clone.rs | 3 +- clippy_lints/src/regex.rs | 3 +- .../src/significant_drop_tightening.rs | 3 +- clippy_lints/src/strings.rs | 3 +- clippy_lints/src/unnecessary_box_returns.rs | 3 +- 20 files changed, 479 insertions(+), 56 deletions(-) create mode 100644 book/src/lint_subgroups.md diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index be13fcbe260f..79de3a700a9b 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -7,6 +7,7 @@ - [Configuration](configuration.md) - [Lint Configuration](lint_configuration.md) - [Clippy's Lints](lints.md) +- [Lint subgroups](lint_subgroups.md) - [Continuous Integration](continuous_integration/README.md) - [GitHub Actions](continuous_integration/github_actions.md) - [GitLab CI](continuous_integration/gitlab.md) diff --git a/book/src/lint_subgroups.md b/book/src/lint_subgroups.md new file mode 100644 index 000000000000..41692ecc8fc4 --- /dev/null +++ b/book/src/lint_subgroups.md @@ -0,0 +1,218 @@ +# Lint subgroups + +Clippy groups its lints into [9 primary categories](lints.md), +two of which are allow-by-default (pedantic and restriction). + +One downside of having such few but broad categories for allow-by-default lints +is that it significantly decreases discoverability, as `restriction` often acts as a blanket category +for any lint that most users likely would not want enforced on their codebase. + +This page should help with that, by defining more granular, unofficial lint (sub)groups. +For example, some people might not be interested in all the style-related `pedantic` lints, +but *are* interested in the `perf`-related ones, so these lints +can additionally be added to the [`perf_pedantic`](#perf_pedantic) subgroup. + + + +## `perf_pedantic` + +These are `pedantic` lints that look for code patterns that could be expressed in a more efficient way. +These would be candidates for the `perf` category, however suggestions made by them can also sometimes hurt readability +and obfuscate the meaning, so occasional `#[allow]`s are expected to be used. + + +Lints: `assigning_clones`, `inefficient_to_string`, `naive_bytecount`, `needless_bitwise_bool`, `trivially_copy_pass_by_ref`, `unnecessary_box_returns`, `unnecessary_join` + +
+#![warn] attribute + +``` +#![warn( + clippy::assigning_clones, + clippy::inefficient_to_string, + clippy::naive_bytecount, + clippy::needless_bitwise_bool, + clippy::trivially_copy_pass_by_ref, + clippy::unnecessary_box_returns, + clippy::unnecessary_join +)] +``` +
+ +
+Lint table + +``` +[lints.clippy] +assigning_clones = "warn" +inefficient_to_string = "warn" +naive_bytecount = "warn" +needless_bitwise_bool = "warn" +trivially_copy_pass_by_ref = "warn" +unnecessary_box_returns = "warn" +unnecessary_join = "warn" +``` +
+ + + +## `perf_restriction` + +These are `restriction` lints that can improve the performance of code, but are very specific +and sometimes *significantly* hurt readability with very little gain in the usual case. +These should ideally only be applied to specific functions or modules that were profiled +and where it is very clear that any performance gain matters. + +As always (but especially here), you should double-check that applying these actually helps +and that any performance wins are worth the introduced complexity. + + +Lints: `format_push_string`, `missing_asserts_for_indexing` + +
+#![warn] attribute + +``` +#![warn( + clippy::format_push_string, + clippy::missing_asserts_for_indexing +)] +``` +
+ +
+Lint table + +``` +[lints.clippy] +format_push_string = "warn" +missing_asserts_for_indexing = "warn" +``` +
+ + +## `perf_nursery` + +These are `nursery` lints that either were previously in the `perf` category or are intended to be in `perf` +but have too many false positives. +Some of them may also be simply wrong in certain situations and end up slower, +so you should make sure to read the description to learn about possible edge cases. + + +Lints: `iter_with_drain`, `mutex_integer`, `needless_collect`, `or_fun_call`, `redundant_clone`, `significant_drop_tightening`, `trivial_regex` + +
+#![warn] attribute + +``` +#![warn( + clippy::iter_with_drain, + clippy::mutex_integer, + clippy::needless_collect, + clippy::or_fun_call, + clippy::redundant_clone, + clippy::significant_drop_tightening, + clippy::trivial_regex +)] +``` +
+ +
+Lint table + +``` +[lints.clippy] +iter_with_drain = "warn" +mutex_integer = "warn" +needless_collect = "warn" +or_fun_call = "warn" +redundant_clone = "warn" +significant_drop_tightening = "warn" +trivial_regex = "warn" +``` +
+ + +## `panic` + +These are `restriction` lints that look for patterns that can introduce panics. + +Usually panics are not something that one should want to avoid and most of the time panicking is perfectly valid +(hence why these lints are in the `restriction` category), +but users may want to forbid any use of panicky functions altogether in specific contexts. + +One use case could be to annotate `GlobalAlloc` impls in which unwinding is Undefined Behavior. + + +Lints: `arithmetic_side_effects`, `expect_used`, `indexing_slicing`, `panic`, `string_slice`, `todo`, `unimplemented`, `unreachable`, `unwrap_used` + +
+#![warn] attribute + +``` +#![warn( + clippy::arithmetic_side_effects, + clippy::expect_used, + clippy::indexing_slicing, + clippy::panic, + clippy::string_slice, + clippy::todo, + clippy::unimplemented, + clippy::unreachable, + clippy::unwrap_used +)] +``` +
+ +
+Lint table + +``` +[lints.clippy] +arithmetic_side_effects = "warn" +expect_used = "warn" +indexing_slicing = "warn" +panic = "warn" +string_slice = "warn" +todo = "warn" +unimplemented = "warn" +unreachable = "warn" +unwrap_used = "warn" +``` +
+ + +## `debug` + +These are lints that can be useful to disable in CI, as they might indicate that code needs more work +or has remaining debugging artifacts. + + +Lints: `dbg_macro`, `todo` + +
+#![warn] attribute + +``` +#![warn( + clippy::dbg_macro, + clippy::todo +)] +``` +
+ +
+Lint table + +``` +[lints.clippy] +dbg_macro = "warn" +todo = "warn" +``` +
+ diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index ad385d5fbd29..fe3ef11f2ef8 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(let_chains)] +#![feature(let_chains, debug_closure_helpers)] #![feature(rustc_private)] #![warn( trivial_casts, diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index d6ed36d52f4e..31af479b6a6d 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -37,6 +37,81 @@ pub fn update(update_mode: UpdateMode) { generate_lint_files(update_mode, &lints, &deprecated_lints, &renamed_lints); } +/// Processes the `book/src/lint_subgroups.md` file +fn process_subgroups(update_mode: UpdateMode, usable_lints: &[Lint]) { + fn lint_formatter<'a>( + lint_names: &'a [&Lint], + delim: &'a str, + write: impl Fn(&str, &mut fmt::Formatter<'_>) -> fmt::Result + 'a, + ) -> impl fmt::Display + 'a { + fmt::from_fn(move |f| { + for (i, lint) in lint_names.iter().copied().enumerate() { + if i > 0 { + f.write_str(delim)?; + } + write(&lint.name, f)?; + } + + Ok(()) + }) + } + + let mut grouped_lints = usable_lints + .iter() + .flat_map(|lint| lint.subgroups.iter().map(move |subgroup| (&**subgroup, lint))) + .into_group_map(); + + replace_region_in_file( + update_mode, + Path::new("book/src/lint_subgroups.md"), + "", + |res, middle| { + let (group_name, _) = middle.trim_start().split_once(' ').unwrap(); + + // Iteratively remove them so that we ideally end up with an empty map at the end if all sections + // exist in the book. This is where we'll also catch any typos in the subgroup names. + let group_lints = grouped_lints.remove(group_name).unwrap_or_default(); + + indoc::writedoc!( + res, + " + {group_name} --> + Lints: {lint_names} + +
+ #![warn] attribute + + ``` + #![warn( + {warn_attrs} + )] + ``` +
+ +
+ Lint table + + ``` + [lints.clippy] + {lint_table} + ``` +
+ ", + lint_names = lint_formatter(&group_lints, ", ", |lint, f| write!(f, "`{lint}`")), + warn_attrs = lint_formatter(&group_lints, ",\n ", |lint, f| write!(f, "clippy::{lint}")), + lint_table = lint_formatter(&group_lints, "\n", |lint, f| write!(f, r#"{lint} = "warn""#)) + ) + .unwrap(); + }, + ); + + assert!( + grouped_lints.is_empty(), + "subgroup book page is missing sections for: {grouped_lints:?}" + ); +} + fn generate_lint_files( update_mode: UpdateMode, lints: &[Lint], @@ -47,12 +122,14 @@ fn generate_lint_files( let mut usable_lints = Lint::usable_lints(lints); usable_lints.sort_by_key(|lint| lint.name.clone()); + process_subgroups(update_mode, &usable_lints); + replace_region_in_file( update_mode, Path::new("README.md"), "[There are over ", " lints included in this crate!]", - |res| { + |res, _| { write!(res, "{}", round_to_fifty(usable_lints.len())).unwrap(); }, ); @@ -62,7 +139,7 @@ fn generate_lint_files( Path::new("book/src/README.md"), "[There are over ", " lints included in this crate!]", - |res| { + |res, _| { write!(res, "{}", round_to_fifty(usable_lints.len())).unwrap(); }, ); @@ -72,7 +149,7 @@ fn generate_lint_files( Path::new("CHANGELOG.md"), "\n", "", - |res| { + |res, _| { for lint in usable_lints .iter() .map(|l| &*l.name) @@ -91,7 +168,7 @@ fn generate_lint_files( Path::new("clippy_lints/src/lib.rs"), "// 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`", - |res| { + |res, _| { for lint_mod in usable_lints.iter().map(|l| &l.module).unique().sorted() { writeln!(res, "mod {lint_mod};").unwrap(); } @@ -527,16 +604,25 @@ struct Lint { desc: String, module: String, declaration_range: Range, + subgroups: Vec, } impl Lint { #[must_use] - fn new(name: &str, group: &str, desc: &str, module: &str, declaration_range: Range) -> Self { + fn new( + name: &str, + group: &str, + desc: &str, + module: &str, + declaration_range: Range, + subgroups: Vec, + ) -> Self { Self { name: name.to_lowercase(), group: group.into(), desc: remove_line_splices(desc), module: module.into(), + subgroups, declaration_range, } } @@ -733,7 +819,9 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec) { let start = range.start; let mut iter = iter .by_ref() - .filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. })); + .filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. })) + .peekable(); + // matches `!{` match_tokens!(iter, Bang OpenBrace); match iter.next() { @@ -762,13 +850,36 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec) { Literal{..}(desc) ); + // If we see a comma now, then a number of subgroups follow, e.g.: + // [perf_pedantic, panic] + let mut subgroups = Vec::new(); + + if iter.next_if(|s| s.token_kind == TokenKind::Comma).is_some() { + match_tokens!(iter, OpenBracket); + + while !matches!( + iter.peek(), + Some(LintDeclSearchResult { + token_kind: TokenKind::CloseBracket, + .. + }) + ) { + if !subgroups.is_empty() { + match_tokens!(iter, Comma); + } + subgroups.push(match_tokens!(iter, Ident(name)).0.to_owned()); + } + + match_tokens!(iter, CloseBracket); + } + if let Some(LintDeclSearchResult { token_kind: TokenKind::CloseBrace, range, .. }) = iter.next() { - lints.push(Lint::new(name, group, desc, module, start..range.end)); + lints.push(Lint::new(name, group, desc, module, start..range.end, subgroups)); } } } @@ -854,13 +965,13 @@ fn remove_line_splices(s: &str) -> String { /// /// # Panics /// -/// Panics if the path could not read or then written +/// Panics if the path could not be read or then written, or if the start/end patterns are not found fn replace_region_in_file( update_mode: UpdateMode, path: &Path, start: &str, end: &str, - write_replacement: impl FnMut(&mut String), + write_replacement: impl FnMut(&mut String, &str), ) { let contents = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read from `{}`: {e}", path.display())); let new_contents = match replace_region_in_text(&contents, start, end, write_replacement) { @@ -879,25 +990,31 @@ fn replace_region_in_file( } } -/// Replaces a region in a text delimited by two strings. Returns the new text if both delimiters -/// were found, or the missing delimiter if not. +/// Repeatedly replaces a region in a text delimited by two strings. Returns the new text if both +/// delimiters were found, or the missing delimiter if not. fn replace_region_in_text<'a>( - text: &str, + mut text: &str, start: &'a str, end: &'a str, - mut write_replacement: impl FnMut(&mut String), + mut write_replacement: impl FnMut(&mut String, &str), ) -> Result { - let (text_start, rest) = text.split_once(start).ok_or(start)?; - let (_, text_end) = rest.split_once(end).ok_or(end)?; - let mut res = String::with_capacity(text.len() + 4096); - res.push_str(text_start); - res.push_str(start); - write_replacement(&mut res); - res.push_str(end); - res.push_str(text_end); + let mut found_start = false; + + while let Some((text_start, rest)) = text.split_once(start) { + let (middle, text_end) = rest.split_once(end).ok_or(end)?; + + res.push_str(text_start); + res.push_str(start); + write_replacement(&mut res, middle); + res.push_str(end); + + text = text_end; + found_start = true; + } - Ok(res) + res.push_str(text); + if found_start { Ok(res) } else { Err(start) } } fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { @@ -973,6 +1090,14 @@ mod tests { pedantic, "single line" } + + declare_clippy_lint!{ + #[clippy::version = "Test version"] + pub DOC_MARKDOWN, + pedantic, + "single line", + [perf_pedantic, panic] + } "#; let mut result = Vec::new(); parse_contents(CONTENTS, "module_name", &mut result); @@ -987,6 +1112,7 @@ mod tests { "\"really long text\"", "module_name", Range::default(), + Vec::new(), ), Lint::new( "doc_markdown", @@ -994,6 +1120,15 @@ mod tests { "\"single line\"", "module_name", Range::default(), + Vec::new(), + ), + Lint::new( + "doc_markdown", + "pedantic", + "\"single line\"", + "module_name", + Range::default(), + vec!["perf_pedantic".into(), "panic".into()], ), ]; assert_eq!(expected, result); @@ -1008,6 +1143,7 @@ mod tests { "\"abc\"", "module_name", Range::default(), + Vec::new(), ), Lint::new( "should_assert_eq2", @@ -1015,6 +1151,7 @@ mod tests { "\"abc\"", "module_name", Range::default(), + Vec::new(), ), Lint::new( "should_assert_eq2", @@ -1022,6 +1159,7 @@ mod tests { "\"abc\"", "module_name", Range::default(), + Vec::new(), ), ]; let expected = vec![Lint::new( @@ -1030,6 +1168,7 @@ mod tests { "\"abc\"", "module_name", Range::default(), + Vec::new(), )]; assert_eq!(expected, Lint::usable_lints(&lints)); } @@ -1037,20 +1176,49 @@ mod tests { #[test] fn test_by_lint_group() { let lints = vec![ - Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), + Lint::new( + "should_assert_eq", + "group1", + "\"abc\"", + "module_name", + Range::default(), + Vec::new(), + ), Lint::new( "should_assert_eq2", "group2", "\"abc\"", "module_name", Range::default(), + Vec::new(), + ), + Lint::new( + "incorrect_match", + "group1", + "\"abc\"", + "module_name", + Range::default(), + Vec::new(), ), - Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), ]; let mut expected: HashMap> = HashMap::new(); expected.insert("group1".to_string(), vec![ - Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), - Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), + Lint::new( + "should_assert_eq", + "group1", + "\"abc\"", + "module_name", + Range::default(), + Vec::new(), + ), + Lint::new( + "incorrect_match", + "group1", + "\"abc\"", + "module_name", + Range::default(), + Vec::new(), + ), ]); expected.insert("group2".to_string(), vec![Lint::new( "should_assert_eq2", @@ -1058,6 +1226,7 @@ mod tests { "\"abc\"", "module_name", Range::default(), + Vec::new(), )]); assert_eq!(expected, Lint::by_lint_group(lints.into_iter())); } diff --git a/clippy_lints/src/assigning_clones.rs b/clippy_lints/src/assigning_clones.rs index 0b82c0cd04c1..08a7009e4be3 100644 --- a/clippy_lints/src/assigning_clones.rs +++ b/clippy_lints/src/assigning_clones.rs @@ -50,7 +50,8 @@ declare_clippy_lint! { #[clippy::version = "1.78.0"] pub ASSIGNING_CLONES, pedantic, - "assigning the result of cloning may be inefficient" + "assigning the result of cloning may be inefficient", + [perf_pedantic] } pub struct AssigningClones { diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs index a96c86f07657..f425392a2039 100644 --- a/clippy_lints/src/dbg_macro.rs +++ b/clippy_lints/src/dbg_macro.rs @@ -31,7 +31,8 @@ declare_clippy_lint! { #[clippy::version = "1.34.0"] pub DBG_MACRO, restriction, - "`dbg!` macro is intended as a debugging tool" + "`dbg!` macro is intended as a debugging tool", + [debug] } pub struct DbgMacro { diff --git a/clippy_lints/src/declare_clippy_lint.rs b/clippy_lints/src/declare_clippy_lint.rs index b1e39c70baa2..4836d5893e53 100644 --- a/clippy_lints/src/declare_clippy_lint.rs +++ b/clippy_lints/src/declare_clippy_lint.rs @@ -1,3 +1,5 @@ +// The $subgroup metavariable is parsed out externally in `clippy_dev/src/update_lints.rs` and just +// ignored here. #[macro_export] #[allow(clippy::crate_in_macro_def)] macro_rules! declare_clippy_lint { @@ -24,7 +26,7 @@ macro_rules! declare_clippy_lint { category: $lintcategory, explanation: concat!($($lit,"\n",)*), location: concat!(file!(), "#L", line!()), - version: $version_expr + version: $version_expr, }; }; ( @@ -33,6 +35,7 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, restriction, $desc:literal + $(,[$($subgroup:ident),+])? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* @@ -46,12 +49,12 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, style, $desc:literal + $(,[$($subgroup:ident),+])? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* pub $lint_name, Warn, crate::LintCategory::Style, $desc, Some($version), $version - } }; ( @@ -60,12 +63,12 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, correctness, $desc:literal + $(,[$($subgroup:ident),+])? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* pub $lint_name, Deny, crate::LintCategory::Correctness, $desc, Some($version), $version - } }; ( @@ -74,6 +77,7 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, perf, $desc:literal + $(,[$($subgroup:ident),+])? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* @@ -87,6 +91,7 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, complexity, $desc:literal + $(,[$($subgroup:ident),+])? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* @@ -100,6 +105,7 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, suspicious, $desc:literal + $(,[$($subgroup:ident),+])? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* @@ -113,6 +119,7 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, nursery, $desc:literal + $(,[$($subgroup:ident),+])? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* @@ -126,6 +133,7 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, pedantic, $desc:literal + $(,[$($subgroup:ident),+])? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* @@ -139,6 +147,7 @@ macro_rules! declare_clippy_lint { pub $lint_name:ident, cargo, $desc:literal + $(,[$($subgroup:ident),+])? ) => { declare_clippy_lint! {@ $(#[doc = $lit])* diff --git a/clippy_lints/src/format_push_string.rs b/clippy_lints/src/format_push_string.rs index 8b1f86cbb913..78d24572f1f7 100644 --- a/clippy_lints/src/format_push_string.rs +++ b/clippy_lints/src/format_push_string.rs @@ -36,7 +36,8 @@ declare_clippy_lint! { #[clippy::version = "1.62.0"] pub FORMAT_PUSH_STRING, restriction, - "`format!(..)` appended to existing `String`" + "`format!(..)` appended to existing `String`", + [perf_restriction] } declare_lint_pass!(FormatPushString => [FORMAT_PUSH_STRING]); diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 22e9674714fe..c5752323c43a 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -79,7 +79,8 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub INDEXING_SLICING, restriction, - "indexing/slicing usage" + "indexing/slicing usage", + [panic] } impl_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING]); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 722290fb68e5..d1c93a918f33 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -303,7 +303,8 @@ declare_clippy_lint! { #[clippy::version = "1.45.0"] pub UNWRAP_USED, restriction, - "using `.unwrap()` on `Result` or `Option`, which should at least get a better message using `expect()`" + "using `.unwrap()` on `Result` or `Option`, which should at least get a better message using `expect()`", + [panic] } declare_clippy_lint! { @@ -366,7 +367,8 @@ declare_clippy_lint! { #[clippy::version = "1.45.0"] pub EXPECT_USED, restriction, - "using `.expect()` on `Result` or `Option`, which might be better handled" + "using `.expect()` on `Result` or `Option`, which might be better handled", + [panic] } declare_clippy_lint! { @@ -937,7 +939,8 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub OR_FUN_CALL, nursery, - "using any `*or` method with a function call, which suggests `*or_else`" + "using any `*or` method with a function call, which suggests `*or_else`", + [perf_nursery] } declare_clippy_lint! { @@ -1084,7 +1087,8 @@ declare_clippy_lint! { #[clippy::version = "1.40.0"] pub INEFFICIENT_TO_STRING, pedantic, - "using `to_string` on `&&T` where `T: ToString`" + "using `to_string` on `&&T` where `T: ToString`", + [perf_pedantic] } declare_clippy_lint! { @@ -1295,7 +1299,8 @@ declare_clippy_lint! { #[clippy::version = "1.61.0"] pub ITER_WITH_DRAIN, nursery, - "replace `.drain(..)` with `.into_iter()`" + "replace `.drain(..)` with `.into_iter()`", + [perf_nursery] } declare_clippy_lint! { @@ -2313,7 +2318,8 @@ declare_clippy_lint! { #[clippy::version = "1.61.0"] pub UNNECESSARY_JOIN, pedantic, - "using `.collect::>().join(\"\")` on an iterator" + "using `.collect::>().join(\"\")` on an iterator", + [perf_pedantic] } declare_clippy_lint! { @@ -2530,7 +2536,8 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub NAIVE_BYTECOUNT, pedantic, - "use of naive `.filter(|&x| x == y).count()` to count byte values" + "use of naive `.filter(|&x| x == y).count()` to count byte values", + [perf_pedantic] } declare_clippy_lint! { @@ -3279,7 +3286,8 @@ declare_clippy_lint! { #[clippy::version = "1.30.0"] pub NEEDLESS_COLLECT, nursery, - "collecting an iterator when collect is not needed" + "collecting an iterator when collect is not needed", + [perf_nursery] } declare_clippy_lint! { diff --git a/clippy_lints/src/missing_asserts_for_indexing.rs b/clippy_lints/src/missing_asserts_for_indexing.rs index d78299fe08be..12e68fabaf22 100644 --- a/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/clippy_lints/src/missing_asserts_for_indexing.rs @@ -61,7 +61,8 @@ declare_clippy_lint! { #[clippy::version = "1.74.0"] pub MISSING_ASSERTS_FOR_INDEXING, restriction, - "indexing into a slice multiple times without an `assert`" + "indexing into a slice multiple times without an `assert`", + [perf_restriction] } declare_lint_pass!(MissingAssertsForIndexing => [MISSING_ASSERTS_FOR_INDEXING]); diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 388414964588..c0d39e07ffc0 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -71,7 +71,8 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub MUTEX_INTEGER, nursery, - "using a mutex for an integer type" + "using a mutex for an integer type", + [perf_nursery] } declare_lint_pass!(Mutex => [MUTEX_ATOMIC, MUTEX_INTEGER]); diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index 9e8a821c3f4e..a1675e426ed8 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -94,7 +94,8 @@ declare_clippy_lint! { #[clippy::version = "1.64.0"] pub ARITHMETIC_SIDE_EFFECTS, restriction, - "any arithmetic expression that can cause side effects like overflows or panics" + "any arithmetic expression that can cause side effects like overflows or panics", + [panic] } declare_clippy_lint! { @@ -766,7 +767,8 @@ declare_clippy_lint! { #[clippy::version = "1.54.0"] pub NEEDLESS_BITWISE_BOOL, pedantic, - "Boolean expressions that use bitwise rather than lazy operators" + "Boolean expressions that use bitwise rather than lazy operators", + [perf_pedantic] } declare_clippy_lint! { diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index fa5b02a5a41b..a1c4455e5223 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -33,7 +33,8 @@ declare_clippy_lint! { #[clippy::version = "1.40.0"] pub PANIC, restriction, - "usage of the `panic!` macro" + "usage of the `panic!` macro", + [panic] } declare_clippy_lint! { @@ -50,7 +51,8 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub UNIMPLEMENTED, restriction, - "`unimplemented!` should not be present in production code" + "`unimplemented!` should not be present in production code", + [panic] } declare_clippy_lint! { @@ -72,7 +74,8 @@ declare_clippy_lint! { #[clippy::version = "1.40.0"] pub TODO, restriction, - "`todo!` should not be present in production code" + "`todo!` should not be present in production code", + [panic, debug] } declare_clippy_lint! { @@ -89,7 +92,8 @@ declare_clippy_lint! { #[clippy::version = "1.40.0"] pub UNREACHABLE, restriction, - "usage of the `unreachable!` macro" + "usage of the `unreachable!` macro", + [panic] } impl_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]); diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 1bddfab39c69..f33ea998c391 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -68,7 +68,8 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub TRIVIALLY_COPY_PASS_BY_REF, pedantic, - "functions taking small copyable arguments by reference" + "functions taking small copyable arguments by reference", + [perf_pedantic] } declare_clippy_lint! { diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index b9e0106fc86b..4bd368458164 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -56,7 +56,8 @@ declare_clippy_lint! { #[clippy::version = "1.32.0"] pub REDUNDANT_CLONE, nursery, - "`clone()` of an owned value that is going to be dropped immediately" + "`clone()` of an owned value that is going to be dropped immediately", + [perf_nursery] } declare_lint_pass!(RedundantClone => [REDUNDANT_CLONE]); diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 6a5bf1b8045d..54d80d013ade 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -52,7 +52,8 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub TRIVIAL_REGEX, nursery, - "trivial regular expressions" + "trivial regular expressions", + [perf_nursery] } declare_clippy_lint! { diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index abd8363456df..41d7d7dc1dbb 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -49,7 +49,8 @@ declare_clippy_lint! { #[clippy::version = "1.69.0"] pub SIGNIFICANT_DROP_TIGHTENING, nursery, - "Searches for elements marked with `#[clippy::has_significant_drop]` that could be early dropped but are in fact dropped at the end of their scopes" + "Searches for elements marked with `#[clippy::has_significant_drop]` that could be early dropped but are in fact dropped at the end of their scopes", + [perf_nursery] } impl_lint_pass!(SignificantDropTightening<'_> => [SIGNIFICANT_DROP_TIGHTENING]); diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index e09c07060065..016b71edcdc1 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -140,7 +140,8 @@ declare_clippy_lint! { #[clippy::version = "1.58.0"] pub STRING_SLICE, restriction, - "slicing a string" + "slicing a string", + [panic] } declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN, STRING_SLICE]); diff --git a/clippy_lints/src/unnecessary_box_returns.rs b/clippy_lints/src/unnecessary_box_returns.rs index 14f4aa6676b6..7583ef77314c 100644 --- a/clippy_lints/src/unnecessary_box_returns.rs +++ b/clippy_lints/src/unnecessary_box_returns.rs @@ -37,7 +37,8 @@ declare_clippy_lint! { #[clippy::version = "1.70.0"] pub UNNECESSARY_BOX_RETURNS, pedantic, - "Needlessly returning a Box" + "Needlessly returning a Box", + [perf_pedantic] } pub struct UnnecessaryBoxReturns {