From 4d93edf34630eec77bbd3d72bb644736528b544c Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 26 Jan 2024 18:48:18 +0100 Subject: [PATCH 001/137] Allow newly added non_local_definitions lint in clippy --- .../undocumented_unsafe_blocks.rs | 2 +- tests/ui/bool_comparison.fixed | 2 +- tests/ui/bool_comparison.rs | 2 +- tests/ui/crashes/ice-4760.rs | 2 + tests/ui/crashes/ice-6179.rs | 1 + tests/ui/explicit_into_iter_loop.fixed | 1 + tests/ui/explicit_into_iter_loop.rs | 1 + tests/ui/explicit_into_iter_loop.stderr | 12 ++--- tests/ui/explicit_iter_loop.fixed | 3 +- tests/ui/explicit_iter_loop.rs | 3 +- tests/ui/explicit_iter_loop.stderr | 36 ++++++------- tests/ui/from_over_into.fixed | 1 + tests/ui/from_over_into.rs | 1 + tests/ui/from_over_into.stderr | 14 ++--- tests/ui/manual_str_repeat.fixed | 1 + tests/ui/manual_str_repeat.rs | 1 + tests/ui/manual_str_repeat.stderr | 20 +++---- tests/ui/needless_borrow.fixed | 1 + tests/ui/needless_borrow.rs | 1 + tests/ui/needless_borrow.stderr | 54 +++++++++---------- 20 files changed, 86 insertions(+), 73 deletions(-) diff --git a/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs b/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs index a278139876064..8997073c8a555 100644 --- a/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs +++ b/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs @@ -4,7 +4,7 @@ //@[disabled] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/undocumented_unsafe_blocks/disabled #![warn(clippy::undocumented_unsafe_blocks, clippy::unnecessary_safety_comment)] -#![allow(deref_nullptr, clippy::let_unit_value, clippy::missing_safety_doc)] +#![allow(deref_nullptr, non_local_definitions, clippy::let_unit_value, clippy::missing_safety_doc)] #![feature(lint_reasons)] extern crate proc_macro_unsafe; diff --git a/tests/ui/bool_comparison.fixed b/tests/ui/bool_comparison.fixed index 02f1d09b83395..600380fd1420d 100644 --- a/tests/ui/bool_comparison.fixed +++ b/tests/ui/bool_comparison.fixed @@ -1,4 +1,4 @@ -#![allow(clippy::needless_if)] +#![allow(non_local_definitions, clippy::needless_if)] #![warn(clippy::bool_comparison)] #![allow(clippy::non_canonical_partial_ord_impl)] diff --git a/tests/ui/bool_comparison.rs b/tests/ui/bool_comparison.rs index 5ef696d855eca..910df6151f8c2 100644 --- a/tests/ui/bool_comparison.rs +++ b/tests/ui/bool_comparison.rs @@ -1,4 +1,4 @@ -#![allow(clippy::needless_if)] +#![allow(non_local_definitions, clippy::needless_if)] #![warn(clippy::bool_comparison)] #![allow(clippy::non_canonical_partial_ord_impl)] diff --git a/tests/ui/crashes/ice-4760.rs b/tests/ui/crashes/ice-4760.rs index 08b06961760ff..e1265169762fc 100644 --- a/tests/ui/crashes/ice-4760.rs +++ b/tests/ui/crashes/ice-4760.rs @@ -1,3 +1,5 @@ +#![allow(non_local_definitions)] + const COUNT: usize = 2; struct Thing; trait Dummy {} diff --git a/tests/ui/crashes/ice-6179.rs b/tests/ui/crashes/ice-6179.rs index ce1895851e2d9..fffc0f7d0d4f2 100644 --- a/tests/ui/crashes/ice-6179.rs +++ b/tests/ui/crashes/ice-6179.rs @@ -3,6 +3,7 @@ #![warn(clippy::use_self)] #![allow(dead_code, clippy::let_with_type_underscore)] +#![allow(non_local_definitions)] struct Foo; diff --git a/tests/ui/explicit_into_iter_loop.fixed b/tests/ui/explicit_into_iter_loop.fixed index 2521bce6a58e1..6d67488a71309 100644 --- a/tests/ui/explicit_into_iter_loop.fixed +++ b/tests/ui/explicit_into_iter_loop.fixed @@ -1,3 +1,4 @@ +#![allow(non_local_definitions)] #![warn(clippy::explicit_into_iter_loop)] fn main() { diff --git a/tests/ui/explicit_into_iter_loop.rs b/tests/ui/explicit_into_iter_loop.rs index 9eac96d182b9f..14630c07c5cc4 100644 --- a/tests/ui/explicit_into_iter_loop.rs +++ b/tests/ui/explicit_into_iter_loop.rs @@ -1,3 +1,4 @@ +#![allow(non_local_definitions)] #![warn(clippy::explicit_into_iter_loop)] fn main() { diff --git a/tests/ui/explicit_into_iter_loop.stderr b/tests/ui/explicit_into_iter_loop.stderr index c03647ab43367..a1e632271ed32 100644 --- a/tests/ui/explicit_into_iter_loop.stderr +++ b/tests/ui/explicit_into_iter_loop.stderr @@ -1,5 +1,5 @@ error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/explicit_into_iter_loop.rs:9:18 + --> $DIR/explicit_into_iter_loop.rs:10:18 | LL | for _ in iterator.into_iter() {} | ^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `iterator` @@ -8,31 +8,31 @@ LL | for _ in iterator.into_iter() {} = help: to override `-D warnings` add `#[allow(clippy::explicit_into_iter_loop)]` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/explicit_into_iter_loop.rs:22:14 + --> $DIR/explicit_into_iter_loop.rs:23:14 | LL | for _ in t.into_iter() {} | ^^^^^^^^^^^^^ help: to write this more concisely, try: `&t` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/explicit_into_iter_loop.rs:25:14 + --> $DIR/explicit_into_iter_loop.rs:26:14 | LL | for _ in r.into_iter() {} | ^^^^^^^^^^^^^ help: to write this more concisely, try: `r` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/explicit_into_iter_loop.rs:33:14 + --> $DIR/explicit_into_iter_loop.rs:34:14 | LL | for _ in mr.into_iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&*mr` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/explicit_into_iter_loop.rs:45:14 + --> $DIR/explicit_into_iter_loop.rs:46:14 | LL | for _ in u.into_iter() {} | ^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut u` error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/explicit_into_iter_loop.rs:48:14 + --> $DIR/explicit_into_iter_loop.rs:49:14 | LL | for _ in mr.into_iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut *mr` diff --git a/tests/ui/explicit_iter_loop.fixed b/tests/ui/explicit_iter_loop.fixed index f08397defa539..06229a52a18c4 100644 --- a/tests/ui/explicit_iter_loop.fixed +++ b/tests/ui/explicit_iter_loop.fixed @@ -5,7 +5,8 @@ clippy::needless_borrow, clippy::deref_addrof, clippy::unnecessary_mut_passed, - dead_code + dead_code, + non_local_definitions, )] use core::slice; diff --git a/tests/ui/explicit_iter_loop.rs b/tests/ui/explicit_iter_loop.rs index 2ee6825d445c2..c2bf45ab2e990 100644 --- a/tests/ui/explicit_iter_loop.rs +++ b/tests/ui/explicit_iter_loop.rs @@ -5,7 +5,8 @@ clippy::needless_borrow, clippy::deref_addrof, clippy::unnecessary_mut_passed, - dead_code + dead_code, + non_local_definitions, )] use core::slice; diff --git a/tests/ui/explicit_iter_loop.stderr b/tests/ui/explicit_iter_loop.stderr index 725d9b63cf8d6..007606b52c294 100644 --- a/tests/ui/explicit_iter_loop.stderr +++ b/tests/ui/explicit_iter_loop.stderr @@ -1,5 +1,5 @@ error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:17:14 + --> $DIR/explicit_iter_loop.rs:18:14 | LL | for _ in vec.iter() {} | ^^^^^^^^^^ help: to write this more concisely, try: `&vec` @@ -11,103 +11,103 @@ LL | #![deny(clippy::explicit_iter_loop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:18:14 + --> $DIR/explicit_iter_loop.rs:19:14 | LL | for _ in vec.iter_mut() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut vec` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:21:14 + --> $DIR/explicit_iter_loop.rs:22:14 | LL | for _ in rvec.iter() {} | ^^^^^^^^^^^ help: to write this more concisely, try: `rvec` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:30:14 + --> $DIR/explicit_iter_loop.rs:31:14 | LL | for _ in [1, 2, 3].iter() {} | ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:34:14 + --> $DIR/explicit_iter_loop.rs:35:14 | LL | for _ in [0; 32].iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:35:14 + --> $DIR/explicit_iter_loop.rs:36:14 | LL | for _ in [0; 33].iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 33]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:38:14 + --> $DIR/explicit_iter_loop.rs:39:14 | LL | for _ in ll.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&ll` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:40:14 + --> $DIR/explicit_iter_loop.rs:41:14 | LL | for _ in rll.iter() {} | ^^^^^^^^^^ help: to write this more concisely, try: `rll` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:43:14 + --> $DIR/explicit_iter_loop.rs:44:14 | LL | for _ in vd.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&vd` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:45:14 + --> $DIR/explicit_iter_loop.rs:46:14 | LL | for _ in rvd.iter() {} | ^^^^^^^^^^ help: to write this more concisely, try: `rvd` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:48:14 + --> $DIR/explicit_iter_loop.rs:49:14 | LL | for _ in bh.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bh` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:51:14 + --> $DIR/explicit_iter_loop.rs:52:14 | LL | for _ in hm.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hm` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:54:14 + --> $DIR/explicit_iter_loop.rs:55:14 | LL | for _ in bt.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bt` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:57:14 + --> $DIR/explicit_iter_loop.rs:58:14 | LL | for _ in hs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hs` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:60:14 + --> $DIR/explicit_iter_loop.rs:61:14 | LL | for _ in bs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bs` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:149:14 + --> $DIR/explicit_iter_loop.rs:150:14 | LL | for _ in x.iter() {} | ^^^^^^^^ help: to write this more concisely, try: `&x` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:150:14 + --> $DIR/explicit_iter_loop.rs:151:14 | LL | for _ in x.iter_mut() {} | ^^^^^^^^^^^^ help: to write this more concisely, try: `&mut x` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/explicit_iter_loop.rs:153:14 + --> $DIR/explicit_iter_loop.rs:154:14 | LL | for _ in r.iter() {} | ^^^^^^^^ help: to write this more concisely, try: `r` diff --git a/tests/ui/from_over_into.fixed b/tests/ui/from_over_into.fixed index 4a68505ee0b1c..a33c1ea5738b9 100644 --- a/tests/ui/from_over_into.fixed +++ b/tests/ui/from_over_into.fixed @@ -1,5 +1,6 @@ #![feature(type_alias_impl_trait)] #![warn(clippy::from_over_into)] +#![allow(non_local_definitions)] #![allow(unused)] // this should throw an error diff --git a/tests/ui/from_over_into.rs b/tests/ui/from_over_into.rs index bf3ed0c2b6422..6cd811ae401e2 100644 --- a/tests/ui/from_over_into.rs +++ b/tests/ui/from_over_into.rs @@ -1,5 +1,6 @@ #![feature(type_alias_impl_trait)] #![warn(clippy::from_over_into)] +#![allow(non_local_definitions)] #![allow(unused)] // this should throw an error diff --git a/tests/ui/from_over_into.stderr b/tests/ui/from_over_into.stderr index f1370ed844fa9..15b4e02a264f1 100644 --- a/tests/ui/from_over_into.stderr +++ b/tests/ui/from_over_into.stderr @@ -1,5 +1,5 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true - --> $DIR/from_over_into.rs:8:1 + --> $DIR/from_over_into.rs:9:1 | LL | impl Into for String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL ~ StringWrapper(val) | error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true - --> $DIR/from_over_into.rs:16:1 + --> $DIR/from_over_into.rs:17:1 | LL | impl Into for String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL ~ SelfType(String::new()) | error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true - --> $DIR/from_over_into.rs:31:1 + --> $DIR/from_over_into.rs:32:1 | LL | impl Into for X { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -42,7 +42,7 @@ LL ~ let _: X = val; | error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true - --> $DIR/from_over_into.rs:43:1 + --> $DIR/from_over_into.rs:44:1 | LL | impl core::convert::Into for crate::ExplicitPaths { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL ~ val.0 | error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true - --> $DIR/from_over_into.rs:63:1 + --> $DIR/from_over_into.rs:64:1 | LL | impl Into for PathInExpansion { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -74,7 +74,7 @@ LL ~ fn from(val: PathInExpansion) -> Self { | error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true - --> $DIR/from_over_into.rs:85:5 + --> $DIR/from_over_into.rs:86:5 | LL | impl Into> for Vec { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -87,7 +87,7 @@ LL ~ FromOverInto(val) | error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true - --> $DIR/from_over_into.rs:95:5 + --> $DIR/from_over_into.rs:96:5 | LL | impl Into<()> for Hello { | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/manual_str_repeat.fixed b/tests/ui/manual_str_repeat.fixed index 888a466278ccc..5f2f1bd9916d8 100644 --- a/tests/ui/manual_str_repeat.fixed +++ b/tests/ui/manual_str_repeat.fixed @@ -1,3 +1,4 @@ +#![allow(non_local_definitions)] #![warn(clippy::manual_str_repeat)] use std::borrow::Cow; diff --git a/tests/ui/manual_str_repeat.rs b/tests/ui/manual_str_repeat.rs index a366351ffa45a..3e3c7f4db4a27 100644 --- a/tests/ui/manual_str_repeat.rs +++ b/tests/ui/manual_str_repeat.rs @@ -1,3 +1,4 @@ +#![allow(non_local_definitions)] #![warn(clippy::manual_str_repeat)] use std::borrow::Cow; diff --git a/tests/ui/manual_str_repeat.stderr b/tests/ui/manual_str_repeat.stderr index 9a13aa9722737..6eb6f2b85a8f4 100644 --- a/tests/ui/manual_str_repeat.stderr +++ b/tests/ui/manual_str_repeat.stderr @@ -1,5 +1,5 @@ error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:7:21 + --> $DIR/manual_str_repeat.rs:8:21 | LL | let _: String = std::iter::repeat("test").take(10).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"test".repeat(10)` @@ -8,55 +8,55 @@ LL | let _: String = std::iter::repeat("test").take(10).collect(); = help: to override `-D warnings` add `#[allow(clippy::manual_str_repeat)]` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:8:21 + --> $DIR/manual_str_repeat.rs:9:21 | LL | let _: String = std::iter::repeat('x').take(10).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"x".repeat(10)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:9:21 + --> $DIR/manual_str_repeat.rs:10:21 | LL | let _: String = std::iter::repeat('\'').take(10).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"'".repeat(10)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:10:21 + --> $DIR/manual_str_repeat.rs:11:21 | LL | let _: String = std::iter::repeat('"').take(10).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"\"".repeat(10)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:14:13 + --> $DIR/manual_str_repeat.rs:15:13 | LL | let _ = repeat(x).take(count + 2).collect::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.repeat(count + 2)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:23:21 + --> $DIR/manual_str_repeat.rs:24:21 | LL | let _: String = repeat(*x).take(count).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*x).repeat(count)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:32:21 + --> $DIR/manual_str_repeat.rs:33:21 | LL | let _: String = repeat(x).take(count).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.repeat(count)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:44:21 + --> $DIR/manual_str_repeat.rs:45:21 | LL | let _: String = repeat(Cow::Borrowed("test")).take(count).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Cow::Borrowed("test").repeat(count)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:47:21 + --> $DIR/manual_str_repeat.rs:48:21 | LL | let _: String = repeat(x).take(count).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.repeat(count)` error: manual implementation of `str::repeat` using iterators - --> $DIR/manual_str_repeat.rs:62:21 + --> $DIR/manual_str_repeat.rs:63:21 | LL | let _: String = std::iter::repeat("test").take(10).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"test".repeat(10)` diff --git a/tests/ui/needless_borrow.fixed b/tests/ui/needless_borrow.fixed index 23e8bf8a468fd..998f5430fdf05 100644 --- a/tests/ui/needless_borrow.fixed +++ b/tests/ui/needless_borrow.fixed @@ -1,6 +1,7 @@ #![feature(lint_reasons)] #![allow( unused, + non_local_definitions, clippy::uninlined_format_args, clippy::unnecessary_mut_passed, clippy::unnecessary_to_owned, diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index 27771a8f15b30..acb2c74d849a2 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -1,6 +1,7 @@ #![feature(lint_reasons)] #![allow( unused, + non_local_definitions, clippy::uninlined_format_args, clippy::unnecessary_mut_passed, clippy::unnecessary_to_owned, diff --git a/tests/ui/needless_borrow.stderr b/tests/ui/needless_borrow.stderr index a21ed8382c14e..9034bd83a0b05 100644 --- a/tests/ui/needless_borrow.stderr +++ b/tests/ui/needless_borrow.stderr @@ -1,5 +1,5 @@ error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:15:15 + --> $DIR/needless_borrow.rs:16:15 | LL | let _ = x(&&a); // warn | ^^^ help: change this to: `&a` @@ -8,157 +8,157 @@ LL | let _ = x(&&a); // warn = help: to override `-D warnings` add `#[allow(clippy::needless_borrow)]` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:19:13 + --> $DIR/needless_borrow.rs:20:13 | LL | mut_ref(&mut &mut b); // warn | ^^^^^^^^^^^ help: change this to: `&mut b` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:31:13 + --> $DIR/needless_borrow.rs:32:13 | LL | &&a | ^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:33:15 + --> $DIR/needless_borrow.rs:34:15 | LL | 46 => &&a, | ^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:39:27 + --> $DIR/needless_borrow.rs:40:27 | LL | break &ref_a; | ^^^^^^ help: change this to: `ref_a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:46:15 + --> $DIR/needless_borrow.rs:47:15 | LL | let _ = x(&&&a); | ^^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:47:15 + --> $DIR/needless_borrow.rs:48:15 | LL | let _ = x(&mut &&a); | ^^^^^^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:48:15 + --> $DIR/needless_borrow.rs:49:15 | LL | let _ = x(&&&mut b); | ^^^^^^^^ help: change this to: `&mut b` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:49:15 + --> $DIR/needless_borrow.rs:50:15 | LL | let _ = x(&&ref_a); | ^^^^^^^ help: change this to: `ref_a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:52:11 + --> $DIR/needless_borrow.rs:53:11 | LL | x(&b); | ^^ help: change this to: `b` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:59:13 + --> $DIR/needless_borrow.rs:60:13 | LL | mut_ref(&mut x); | ^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:60:13 + --> $DIR/needless_borrow.rs:61:13 | LL | mut_ref(&mut &mut x); | ^^^^^^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:61:23 + --> $DIR/needless_borrow.rs:62:23 | LL | let y: &mut i32 = &mut x; | ^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:62:23 + --> $DIR/needless_borrow.rs:63:23 | LL | let y: &mut i32 = &mut &mut x; | ^^^^^^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:71:14 + --> $DIR/needless_borrow.rs:72:14 | LL | 0 => &mut x, | ^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:77:14 + --> $DIR/needless_borrow.rs:78:14 | LL | 0 => &mut x, | ^^^^^^ help: change this to: `x` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:89:13 + --> $DIR/needless_borrow.rs:90:13 | LL | let _ = (&x).0; | ^^^^ help: change this to: `x` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:91:22 + --> $DIR/needless_borrow.rs:92:22 | LL | let _ = unsafe { (&*x).0 }; | ^^^^^ help: change this to: `(*x)` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:101:5 + --> $DIR/needless_borrow.rs:102:5 | LL | (&&()).foo(); | ^^^^^^ help: change this to: `(&())` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:110:5 + --> $DIR/needless_borrow.rs:111:5 | LL | (&&5).foo(); | ^^^^^ help: change this to: `(&5)` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:136:23 + --> $DIR/needless_borrow.rs:137:23 | LL | let x: (&str,) = (&"",); | ^^^ help: change this to: `""` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:178:13 + --> $DIR/needless_borrow.rs:179:13 | LL | (&self.f)() | ^^^^^^^^^ help: change this to: `(self.f)` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:187:13 + --> $DIR/needless_borrow.rs:188:13 | LL | (&mut self.f)() | ^^^^^^^^^^^^^ help: change this to: `(self.f)` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:224:22 + --> $DIR/needless_borrow.rs:225:22 | LL | let _ = &mut (&mut { x.u }).x; | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:231:22 + --> $DIR/needless_borrow.rs:232:22 | LL | let _ = &mut (&mut { x.u }).x; | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:235:22 + --> $DIR/needless_borrow.rs:236:22 | LL | let _ = &mut (&mut x.u).x; | ^^^^^^^^^^ help: change this to: `x.u` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:236:22 + --> $DIR/needless_borrow.rs:237:22 | LL | let _ = &mut (&mut { x.u }).x; | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` From 66e475794d27f58d3fa6928c0c8858c42302379e Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Sun, 25 Feb 2024 22:22:09 +0100 Subject: [PATCH 002/137] Add `ast::ExprKind::Dummy` --- clippy_utils/src/ast_utils.rs | 1 + clippy_utils/src/sugg.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 0467a8a65709a..81a26a12009d1 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -144,6 +144,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Paren(l), _) => eq_expr(l, r), (_, Paren(r)) => eq_expr(l, r), (Err, Err) => true, + (Dummy, _) | (_, Dummy) => unreachable!("comparing `ExprKind::Dummy`"), (Try(l), Try(r)) | (Await(l, _), Await(r, _)) => eq_expr(l, r), (Array(l), Array(r)) => over(l, r, |l, r| eq_expr(l, r)), (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)), diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index b355e66b7b12a..7b1b0388b29f3 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -222,7 +222,8 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Array(..) | ast::ExprKind::While(..) | ast::ExprKind::Await(..) - | ast::ExprKind::Err => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0), + | ast::ExprKind::Err + | ast::ExprKind::Dummy => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0), ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp( AssocOp::DotDot, lhs.as_ref().map_or("".into(), |lhs| { From ef2039effc824936a673cda3ae17ec926e686656 Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Sun, 25 Feb 2024 22:22:11 +0100 Subject: [PATCH 003/137] Add `ErrorGuaranteed` to `ast::ExprKind::Err` --- clippy_utils/src/ast_utils.rs | 2 +- clippy_utils/src/sugg.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 81a26a12009d1..c52a4e0d8b7c7 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -143,7 +143,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { match (&l.kind, &r.kind) { (Paren(l), _) => eq_expr(l, r), (_, Paren(r)) => eq_expr(l, r), - (Err, Err) => true, + (Err(_), Err(_)) => true, (Dummy, _) | (_, Dummy) => unreachable!("comparing `ExprKind::Dummy`"), (Try(l), Try(r)) | (Await(l, _), Await(r, _)) => eq_expr(l, r), (Array(l), Array(r)) => over(l, r, |l, r| eq_expr(l, r)), diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 7b1b0388b29f3..1f6446b8746e6 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -222,7 +222,7 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Array(..) | ast::ExprKind::While(..) | ast::ExprKind::Await(..) - | ast::ExprKind::Err + | ast::ExprKind::Err(_) | ast::ExprKind::Dummy => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0), ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp( AssocOp::DotDot, From d85642e6e80c448f8e3bf0797d381d434f472496 Mon Sep 17 00:00:00 2001 From: "Christopher B. Speir" Date: Sat, 24 Feb 2024 20:10:29 -0600 Subject: [PATCH 004/137] Alphabetize configuration options and lints in Clippy doc --- CHANGELOG.md | 110 ++-- book/src/lint_configuration.md | 884 ++++++++++++++++----------------- clippy_config/src/conf.rs | 6 +- clippy_config/src/metadata.rs | 4 +- 4 files changed, 504 insertions(+), 500 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26dce1f926572..e2b78c89dda6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5815,74 +5815,74 @@ Released 2018-09-13 [`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset +[`absolute-paths-allowed-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-allowed-crates +[`absolute-paths-max-segments`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-max-segments +[`accept-comment-above-attributes`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-attributes +[`accept-comment-above-statement`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-statement +[`allow-comparison-to-zero`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-comparison-to-zero +[`allow-dbg-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-dbg-in-tests +[`allow-expect-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-tests +[`allow-mixed-uninlined-format-args`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-mixed-uninlined-format-args +[`allow-one-hash-in-raw-strings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-one-hash-in-raw-strings +[`allow-print-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-print-in-tests +[`allow-private-module-inception`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-private-module-inception +[`allow-unwrap-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-unwrap-in-tests +[`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles +[`allowed-duplicate-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-duplicate-crates +[`allowed-idents-below-min-chars`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-idents-below-min-chars +[`allowed-scripts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-scripts +[`allowed-wildcard-imports`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-wildcard-imports [`arithmetic-side-effects-allowed`]: https://doc.rust-lang.org/clippy/lint_configuration.html#arithmetic-side-effects-allowed [`arithmetic-side-effects-allowed-binary`]: https://doc.rust-lang.org/clippy/lint_configuration.html#arithmetic-side-effects-allowed-binary [`arithmetic-side-effects-allowed-unary`]: https://doc.rust-lang.org/clippy/lint_configuration.html#arithmetic-side-effects-allowed-unary +[`array-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#array-size-threshold [`avoid-breaking-exported-api`]: https://doc.rust-lang.org/clippy/lint_configuration.html#avoid-breaking-exported-api -[`msrv`]: https://doc.rust-lang.org/clippy/lint_configuration.html#msrv +[`await-holding-invalid-types`]: https://doc.rust-lang.org/clippy/lint_configuration.html#await-holding-invalid-types +[`cargo-ignore-publish`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cargo-ignore-publish +[`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items [`cognitive-complexity-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cognitive-complexity-threshold -[`excessive-nesting-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#excessive-nesting-threshold +[`disallowed-macros`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-macros +[`disallowed-methods`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-methods [`disallowed-names`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-names -[`semicolon-inside-block-ignore-singleline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-inside-block-ignore-singleline -[`semicolon-outside-block-ignore-multiline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-outside-block-ignore-multiline +[`disallowed-types`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-types [`doc-valid-idents`]: https://doc.rust-lang.org/clippy/lint_configuration.html#doc-valid-idents -[`too-many-arguments-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-many-arguments-threshold -[`type-complexity-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#type-complexity-threshold -[`single-char-binding-names-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#single-char-binding-names-threshold -[`too-large-for-stack`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-large-for-stack +[`enable-raw-pointer-heuristic-for-send`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enable-raw-pointer-heuristic-for-send +[`enforce-iter-loop-reborrow`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enforce-iter-loop-reborrow +[`enforced-import-renames`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enforced-import-renames [`enum-variant-name-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enum-variant-name-threshold -[`struct-field-name-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#struct-field-name-threshold [`enum-variant-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enum-variant-size-threshold -[`verbose-bit-mask-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#verbose-bit-mask-threshold +[`excessive-nesting-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#excessive-nesting-threshold +[`future-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#future-size-threshold +[`ignore-interior-mutability`]: https://doc.rust-lang.org/clippy/lint_configuration.html#ignore-interior-mutability +[`large-error-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#large-error-threshold [`literal-representation-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#literal-representation-threshold -[`trivial-copy-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#trivial-copy-size-limit +[`matches-for-let-else`]: https://doc.rust-lang.org/clippy/lint_configuration.html#matches-for-let-else +[`max-fn-params-bools`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-fn-params-bools +[`max-include-file-size`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-include-file-size +[`max-struct-bools`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-struct-bools +[`max-suggested-slice-pattern-length`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-suggested-slice-pattern-length +[`max-trait-bounds`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-trait-bounds +[`min-ident-chars-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#min-ident-chars-threshold +[`missing-docs-in-crate-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#missing-docs-in-crate-items +[`msrv`]: https://doc.rust-lang.org/clippy/lint_configuration.html#msrv [`pass-by-value-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pass-by-value-size-limit -[`too-many-lines-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-many-lines-threshold -[`array-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#array-size-threshold +[`pub-underscore-fields-behavior`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pub-underscore-fields-behavior +[`semicolon-inside-block-ignore-singleline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-inside-block-ignore-singleline +[`semicolon-outside-block-ignore-multiline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-outside-block-ignore-multiline +[`single-char-binding-names-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#single-char-binding-names-threshold [`stack-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#stack-size-threshold -[`vec-box-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#vec-box-size-threshold -[`max-trait-bounds`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-trait-bounds -[`max-struct-bools`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-struct-bools -[`max-fn-params-bools`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-fn-params-bools -[`warn-on-all-wildcard-imports`]: https://doc.rust-lang.org/clippy/lint_configuration.html#warn-on-all-wildcard-imports -[`disallowed-macros`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-macros -[`disallowed-methods`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-methods -[`disallowed-types`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-types -[`unreadable-literal-lint-fractions`]: https://doc.rust-lang.org/clippy/lint_configuration.html#unreadable-literal-lint-fractions -[`upper-case-acronyms-aggressive`]: https://doc.rust-lang.org/clippy/lint_configuration.html#upper-case-acronyms-aggressive -[`matches-for-let-else`]: https://doc.rust-lang.org/clippy/lint_configuration.html#matches-for-let-else -[`cargo-ignore-publish`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cargo-ignore-publish [`standard-macro-braces`]: https://doc.rust-lang.org/clippy/lint_configuration.html#standard-macro-braces -[`enforced-import-renames`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enforced-import-renames -[`allowed-scripts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-scripts -[`enable-raw-pointer-heuristic-for-send`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enable-raw-pointer-heuristic-for-send -[`max-suggested-slice-pattern-length`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-suggested-slice-pattern-length -[`await-holding-invalid-types`]: https://doc.rust-lang.org/clippy/lint_configuration.html#await-holding-invalid-types -[`max-include-file-size`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-include-file-size -[`allow-expect-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-tests -[`allow-unwrap-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-unwrap-in-tests -[`allow-dbg-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-dbg-in-tests -[`allow-print-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-print-in-tests -[`large-error-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#large-error-threshold -[`ignore-interior-mutability`]: https://doc.rust-lang.org/clippy/lint_configuration.html#ignore-interior-mutability -[`allow-mixed-uninlined-format-args`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-mixed-uninlined-format-args +[`struct-field-name-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#struct-field-name-threshold [`suppress-restriction-lint-in-const`]: https://doc.rust-lang.org/clippy/lint_configuration.html#suppress-restriction-lint-in-const -[`missing-docs-in-crate-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#missing-docs-in-crate-items -[`future-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#future-size-threshold +[`too-large-for-stack`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-large-for-stack +[`too-many-arguments-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-many-arguments-threshold +[`too-many-lines-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-many-lines-threshold +[`trivial-copy-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#trivial-copy-size-limit +[`type-complexity-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#type-complexity-threshold [`unnecessary-box-size`]: https://doc.rust-lang.org/clippy/lint_configuration.html#unnecessary-box-size -[`allow-private-module-inception`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-private-module-inception -[`allowed-idents-below-min-chars`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-idents-below-min-chars -[`min-ident-chars-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#min-ident-chars-threshold -[`accept-comment-above-statement`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-statement -[`accept-comment-above-attributes`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-attributes -[`allow-one-hash-in-raw-strings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-one-hash-in-raw-strings -[`absolute-paths-max-segments`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-max-segments -[`absolute-paths-allowed-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-allowed-crates -[`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles -[`allowed-duplicate-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-duplicate-crates -[`enforce-iter-loop-reborrow`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enforce-iter-loop-reborrow -[`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items -[`pub-underscore-fields-behavior`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pub-underscore-fields-behavior -[`allow-comparison-to-zero`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-comparison-to-zero -[`allowed-wildcard-imports`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-wildcard-imports +[`unreadable-literal-lint-fractions`]: https://doc.rust-lang.org/clippy/lint_configuration.html#unreadable-literal-lint-fractions +[`upper-case-acronyms-aggressive`]: https://doc.rust-lang.org/clippy/lint_configuration.html#upper-case-acronyms-aggressive +[`vec-box-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#vec-box-size-threshold +[`verbose-bit-mask-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#verbose-bit-mask-threshold +[`warn-on-all-wildcard-imports`]: https://doc.rust-lang.org/clippy/lint_configuration.html#warn-on-all-wildcard-imports diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 214a60d3bfdf7..a985346b3c05f 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -10,455 +10,505 @@ and lints affected. --- -## `arithmetic-side-effects-allowed` -Suppress checking of the passed type names in all types of operations. - -If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead. +## `absolute-paths-allowed-crates` +Which crates to allow absolute paths from -#### Example +**Default Value:** `[]` -```toml -arithmetic-side-effects-allowed = ["SomeType", "AnotherType"] -``` +--- +**Affected lints:** +* [`absolute_paths`](https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths) -#### Noteworthy -A type, say `SomeType`, listed in this configuration has the same behavior of -`["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`. +## `absolute-paths-max-segments` +The maximum number of segments a path can have before being linted, anything above this will +be linted. -**Default Value:** `[]` +**Default Value:** `2` --- **Affected lints:** -* [`arithmetic_side_effects`](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects) +* [`absolute_paths`](https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths) -## `arithmetic-side-effects-allowed-binary` -Suppress checking of the passed type pair names in binary operations like addition or -multiplication. +## `accept-comment-above-attributes` +Whether to accept a safety comment to be placed above the attributes for the `unsafe` block -Supports the "*" wildcard to indicate that a certain type won't trigger the lint regardless -of the involved counterpart. For example, `["SomeType", "*"]` or `["*", "AnotherType"]`. +**Default Value:** `true` -Pairs are asymmetric, which means that `["SomeType", "AnotherType"]` is not the same as -`["AnotherType", "SomeType"]`. +--- +**Affected lints:** +* [`undocumented_unsafe_blocks`](https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks) -#### Example -```toml -arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]] -``` +## `accept-comment-above-statement` +Whether to accept a safety comment to be placed above the statement containing the `unsafe` block -**Default Value:** `[]` +**Default Value:** `true` --- **Affected lints:** -* [`arithmetic_side_effects`](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects) +* [`undocumented_unsafe_blocks`](https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks) -## `arithmetic-side-effects-allowed-unary` -Suppress checking of the passed type names in unary operations like "negation" (`-`). +## `allow-comparison-to-zero` +Don't lint when comparing the result of a modulo operation to zero. -#### Example +**Default Value:** `true` -```toml -arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] -``` +--- +**Affected lints:** +* [`modulo_arithmetic`](https://rust-lang.github.io/rust-clippy/master/index.html#modulo_arithmetic) -**Default Value:** `[]` + +## `allow-dbg-in-tests` +Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` + +**Default Value:** `false` --- **Affected lints:** -* [`arithmetic_side_effects`](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects) +* [`dbg_macro`](https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro) -## `avoid-breaking-exported-api` -Suppress lints whenever the suggested change would cause breakage for other crates. +## `allow-expect-in-tests` +Whether `expect` should be allowed in test functions or `#[cfg(test)]` -**Default Value:** `true` +**Default Value:** `false` --- **Affected lints:** -* [`enum_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names) -* [`large_types_passed_by_value`](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value) -* [`trivially_copy_pass_by_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref) -* [`unnecessary_wraps`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps) -* [`unused_self`](https://rust-lang.github.io/rust-clippy/master/index.html#unused_self) -* [`upper_case_acronyms`](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms) -* [`wrong_self_convention`](https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention) -* [`box_collection`](https://rust-lang.github.io/rust-clippy/master/index.html#box_collection) -* [`redundant_allocation`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation) -* [`rc_buffer`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer) -* [`vec_box`](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box) -* [`option_option`](https://rust-lang.github.io/rust-clippy/master/index.html#option_option) -* [`linkedlist`](https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist) -* [`rc_mutex`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex) -* [`unnecessary_box_returns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns) -* [`single_call_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#single_call_fn) +* [`expect_used`](https://rust-lang.github.io/rust-clippy/master/index.html#expect_used) -## `msrv` -The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml` +## `allow-mixed-uninlined-format-args` +Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` + +**Default Value:** `true` --- **Affected lints:** -* [`manual_split_once`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once) -* [`manual_str_repeat`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat) -* [`cloned_instead_of_copied`](https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied) -* [`redundant_field_names`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names) -* [`option_map_unwrap_or`](https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or) -* [`redundant_static_lifetimes`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes) -* [`filter_map_next`](https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next) -* [`checked_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions) -* [`manual_range_contains`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains) -* [`use_self`](https://rust-lang.github.io/rust-clippy/master/index.html#use_self) -* [`mem_replace_with_default`](https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default) -* [`manual_non_exhaustive`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive) -* [`option_as_ref_deref`](https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref) -* [`map_unwrap_or`](https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or) -* [`match_like_matches_macro`](https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro) -* [`manual_strip`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip) -* [`missing_const_for_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn) -* [`unnested_or_patterns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns) -* [`from_over_into`](https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into) -* [`ptr_as_ptr`](https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr) -* [`if_then_some_else_none`](https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none) -* [`approx_constant`](https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant) -* [`deprecated_cfg_attr`](https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr) -* [`index_refutable_slice`](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice) -* [`map_clone`](https://rust-lang.github.io/rust-clippy/master/index.html#map_clone) -* [`borrow_as_ptr`](https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr) -* [`manual_bits`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits) -* [`err_expect`](https://rust-lang.github.io/rust-clippy/master/index.html#err_expect) -* [`cast_abs_to_unsigned`](https://rust-lang.github.io/rust-clippy/master/index.html#cast_abs_to_unsigned) * [`uninlined_format_args`](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args) -* [`manual_clamp`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp) -* [`manual_let_else`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else) -* [`unchecked_duration_subtraction`](https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction) -* [`collapsible_str_replace`](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_str_replace) -* [`seek_from_current`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current) -* [`seek_rewind`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_rewind) -* [`unnecessary_lazy_evaluations`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations) -* [`transmute_ptr_to_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref) -* [`almost_complete_range`](https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range) -* [`needless_borrow`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow) -* [`derivable_impls`](https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls) -* [`manual_is_ascii_check`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check) -* [`manual_rem_euclid`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid) -* [`manual_retain`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain) -* [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds) -* [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions) -* [`manual_try_fold`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold) -* [`manual_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one) -* [`iter_kv_map`](https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map) -* [`manual_c_str_literals`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals) -## `cognitive-complexity-threshold` -The maximum cognitive complexity a function can have +## `allow-one-hash-in-raw-strings` +Whether to allow `r#""#` when `r""` can be used -**Default Value:** `25` +**Default Value:** `false` --- **Affected lints:** -* [`cognitive_complexity`](https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity) +* [`unnecessary_raw_string_hashes`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_raw_string_hashes) -## `excessive-nesting-threshold` -The maximum amount of nesting a block can reside in +## `allow-print-in-tests` +Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]` -**Default Value:** `0` +**Default Value:** `false` --- **Affected lints:** -* [`excessive_nesting`](https://rust-lang.github.io/rust-clippy/master/index.html#excessive_nesting) +* [`print_stderr`](https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr) +* [`print_stdout`](https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout) -## `disallowed-names` -The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value -`".."` can be used as part of the list to indicate that the configured values should be appended to the -default configuration of Clippy. By default, any configuration will replace the default value. +## `allow-private-module-inception` +Whether to allow module inception if it's not public. -**Default Value:** `["foo", "baz", "quux"]` +**Default Value:** `false` --- **Affected lints:** -* [`disallowed_names`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names) +* [`module_inception`](https://rust-lang.github.io/rust-clippy/master/index.html#module_inception) -## `semicolon-inside-block-ignore-singleline` -Whether to lint only if it's multiline. +## `allow-unwrap-in-tests` +Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` **Default Value:** `false` --- **Affected lints:** -* [`semicolon_inside_block`](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_inside_block) +* [`unwrap_used`](https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used) -## `semicolon-outside-block-ignore-multiline` -Whether to lint only if it's singleline. +## `allowed-dotfiles` +Additional dotfiles (files or directories starting with a dot) to allow -**Default Value:** `false` +**Default Value:** `[]` --- **Affected lints:** -* [`semicolon_outside_block`](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block) +* [`path_ends_with_ext`](https://rust-lang.github.io/rust-clippy/master/index.html#path_ends_with_ext) -## `doc-valid-idents` -The list of words this lint should not consider as identifiers needing ticks. The value -`".."` can be used as part of the list to indicate, that the configured values should be appended to the -default configuration of Clippy. By default, any configuration will replace the default value. For example: -* `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. -* `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. +## `allowed-duplicate-crates` +A list of crate names to allow duplicates of -**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` +**Default Value:** `[]` --- **Affected lints:** -* [`doc_markdown`](https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown) +* [`multiple_crate_versions`](https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions) -## `too-many-arguments-threshold` -The maximum number of argument a function or method can have +## `allowed-idents-below-min-chars` +Allowed names below the minimum allowed characters. The value `".."` can be used as part of +the list to indicate, that the configured values should be appended to the default +configuration of Clippy. By default, any configuration will replace the default value. -**Default Value:** `7` +**Default Value:** `["j", "z", "i", "y", "n", "x", "w"]` --- **Affected lints:** -* [`too_many_arguments`](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments) +* [`min_ident_chars`](https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars) -## `type-complexity-threshold` -The maximum complexity a type can have +## `allowed-scripts` +The list of unicode scripts allowed to be used in the scope. -**Default Value:** `250` +**Default Value:** `["Latin"]` --- **Affected lints:** -* [`type_complexity`](https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity) +* [`disallowed_script_idents`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents) -## `single-char-binding-names-threshold` -The maximum number of single char bindings a scope may have +## `allowed-wildcard-imports` +List of path segments allowed to have wildcard imports. -**Default Value:** `4` +#### Example + +```toml +allowed-wildcard-imports = [ "utils", "common" ] +``` + +#### Noteworthy + +1. This configuration has no effects if used with `warn_on_all_wildcard_imports = true`. +2. Paths with any segment that containing the word 'prelude' +are already allowed by default. + +**Default Value:** `[]` --- **Affected lints:** -* [`many_single_char_names`](https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names) +* [`wildcard_imports`](https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports) -## `too-large-for-stack` -The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap +## `arithmetic-side-effects-allowed` +Suppress checking of the passed type names in all types of operations. -**Default Value:** `200` +If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead. + +#### Example + +```toml +arithmetic-side-effects-allowed = ["SomeType", "AnotherType"] +``` + +#### Noteworthy + +A type, say `SomeType`, listed in this configuration has the same behavior of +`["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`. + +**Default Value:** `[]` --- **Affected lints:** -* [`boxed_local`](https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local) -* [`useless_vec`](https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec) +* [`arithmetic_side_effects`](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects) -## `enum-variant-name-threshold` -The minimum number of enum variants for the lints about variant names to trigger +## `arithmetic-side-effects-allowed-binary` +Suppress checking of the passed type pair names in binary operations like addition or +multiplication. -**Default Value:** `3` +Supports the "*" wildcard to indicate that a certain type won't trigger the lint regardless +of the involved counterpart. For example, `["SomeType", "*"]` or `["*", "AnotherType"]`. + +Pairs are asymmetric, which means that `["SomeType", "AnotherType"]` is not the same as +`["AnotherType", "SomeType"]`. + +#### Example + +```toml +arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]] +``` + +**Default Value:** `[]` + +--- +**Affected lints:** +* [`arithmetic_side_effects`](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects) + + +## `arithmetic-side-effects-allowed-unary` +Suppress checking of the passed type names in unary operations like "negation" (`-`). + +#### Example + +```toml +arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] +``` + +**Default Value:** `[]` + +--- +**Affected lints:** +* [`arithmetic_side_effects`](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects) + + +## `array-size-threshold` +The maximum allowed size for arrays on the stack + +**Default Value:** `512000` --- **Affected lints:** +* [`large_const_arrays`](https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays) +* [`large_stack_arrays`](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays) + + +## `avoid-breaking-exported-api` +Suppress lints whenever the suggested change would cause breakage for other crates. + +**Default Value:** `true` + +--- +**Affected lints:** +* [`box_collection`](https://rust-lang.github.io/rust-clippy/master/index.html#box_collection) * [`enum_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names) +* [`large_types_passed_by_value`](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value) +* [`linkedlist`](https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist) +* [`option_option`](https://rust-lang.github.io/rust-clippy/master/index.html#option_option) +* [`rc_buffer`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer) +* [`rc_mutex`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex) +* [`redundant_allocation`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation) +* [`single_call_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#single_call_fn) +* [`trivially_copy_pass_by_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref) +* [`unnecessary_box_returns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns) +* [`unnecessary_wraps`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps) +* [`unused_self`](https://rust-lang.github.io/rust-clippy/master/index.html#unused_self) +* [`upper_case_acronyms`](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms) +* [`vec_box`](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box) +* [`wrong_self_convention`](https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention) -## `struct-field-name-threshold` -The minimum number of struct fields for the lints about field names to trigger +## `await-holding-invalid-types` -**Default Value:** `3` + +**Default Value:** `[]` --- **Affected lints:** -* [`struct_field_names`](https://rust-lang.github.io/rust-clippy/master/index.html#struct_field_names) +* [`await_holding_invalid_type`](https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_invalid_type) -## `enum-variant-size-threshold` -The maximum size of an enum's variant to avoid box suggestion +## `cargo-ignore-publish` +For internal testing only, ignores the current `publish` settings in the Cargo manifest. -**Default Value:** `200` +**Default Value:** `false` --- **Affected lints:** -* [`large_enum_variant`](https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant) +* [`cargo_common_metadata`](https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata) -## `verbose-bit-mask-threshold` -The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros' +## `check-private-items` +Whether to also run the listed lints on private items. -**Default Value:** `1` +**Default Value:** `false` --- **Affected lints:** -* [`verbose_bit_mask`](https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask) +* [`missing_errors_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc) +* [`missing_panics_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc) +* [`missing_safety_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc) +* [`unnecessary_safety_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_doc) -## `literal-representation-threshold` -The lower bound for linting decimal literals +## `cognitive-complexity-threshold` +The maximum cognitive complexity a function can have -**Default Value:** `16384` +**Default Value:** `25` --- **Affected lints:** -* [`decimal_literal_representation`](https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation) +* [`cognitive_complexity`](https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity) -## `trivial-copy-size-limit` -The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by -reference. By default there is no limit +## `disallowed-macros` +The list of disallowed macros, written as fully qualified paths. + +**Default Value:** `[]` --- **Affected lints:** -* [`trivially_copy_pass_by_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref) +* [`disallowed_macros`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros) -## `pass-by-value-size-limit` -The minimum size (in bytes) to consider a type for passing by reference instead of by value. +## `disallowed-methods` +The list of disallowed methods, written as fully qualified paths. -**Default Value:** `256` +**Default Value:** `[]` --- **Affected lints:** -* [`large_types_passed_by_value`](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value) +* [`disallowed_methods`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods) -## `too-many-lines-threshold` -The maximum number of lines a function or method can have +## `disallowed-names` +The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value +`".."` can be used as part of the list to indicate that the configured values should be appended to the +default configuration of Clippy. By default, any configuration will replace the default value. -**Default Value:** `100` +**Default Value:** `["foo", "baz", "quux"]` --- **Affected lints:** -* [`too_many_lines`](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines) +* [`disallowed_names`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names) -## `array-size-threshold` -The maximum allowed size for arrays on the stack +## `disallowed-types` +The list of disallowed types, written as fully qualified paths. -**Default Value:** `512000` +**Default Value:** `[]` --- **Affected lints:** -* [`large_stack_arrays`](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays) -* [`large_const_arrays`](https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays) +* [`disallowed_types`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types) -## `stack-size-threshold` -The maximum allowed stack size for functions in bytes +## `doc-valid-idents` +The list of words this lint should not consider as identifiers needing ticks. The value +`".."` can be used as part of the list to indicate, that the configured values should be appended to the +default configuration of Clippy. By default, any configuration will replace the default value. For example: +* `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. +* `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. -**Default Value:** `512000` +**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` --- **Affected lints:** -* [`large_stack_frames`](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_frames) +* [`doc_markdown`](https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown) -## `vec-box-size-threshold` -The size of the boxed type in bytes, where boxing in a `Vec` is allowed +## `enable-raw-pointer-heuristic-for-send` +Whether to apply the raw pointer heuristic to determine if a type is `Send`. -**Default Value:** `4096` +**Default Value:** `true` --- **Affected lints:** -* [`vec_box`](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box) +* [`non_send_fields_in_send_ty`](https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty) -## `max-trait-bounds` -The maximum number of bounds a trait can have to be linted +## `enforce-iter-loop-reborrow` +Whether to recommend using implicit into iter for reborrowed values. -**Default Value:** `3` +#### Example +```no_run +let mut vec = vec![1, 2, 3]; +let rmvec = &mut vec; +for _ in rmvec.iter() {} +for _ in rmvec.iter_mut() {} +``` + +Use instead: +```no_run +let mut vec = vec![1, 2, 3]; +let rmvec = &mut vec; +for _ in &*rmvec {} +for _ in &mut *rmvec {} +``` + +**Default Value:** `false` --- **Affected lints:** -* [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds) +* [`explicit_iter_loop`](https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop) -## `max-struct-bools` -The maximum number of bool fields a struct can have +## `enforced-import-renames` +The list of imports to always rename, a fully qualified path followed by the rename. -**Default Value:** `3` +**Default Value:** `[]` --- **Affected lints:** -* [`struct_excessive_bools`](https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools) +* [`missing_enforced_import_renames`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames) -## `max-fn-params-bools` -The maximum number of bool parameters a function can have +## `enum-variant-name-threshold` +The minimum number of enum variants for the lints about variant names to trigger **Default Value:** `3` --- **Affected lints:** -* [`fn_params_excessive_bools`](https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools) +* [`enum_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names) -## `warn-on-all-wildcard-imports` -Whether to allow certain wildcard imports (prelude, super in tests). +## `enum-variant-size-threshold` +The maximum size of an enum's variant to avoid box suggestion -**Default Value:** `false` +**Default Value:** `200` --- **Affected lints:** -* [`wildcard_imports`](https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports) +* [`large_enum_variant`](https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant) -## `disallowed-macros` -The list of disallowed macros, written as fully qualified paths. +## `excessive-nesting-threshold` +The maximum amount of nesting a block can reside in -**Default Value:** `[]` +**Default Value:** `0` --- **Affected lints:** -* [`disallowed_macros`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros) +* [`excessive_nesting`](https://rust-lang.github.io/rust-clippy/master/index.html#excessive_nesting) -## `disallowed-methods` -The list of disallowed methods, written as fully qualified paths. +## `future-size-threshold` +The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint -**Default Value:** `[]` +**Default Value:** `16384` --- **Affected lints:** -* [`disallowed_methods`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods) +* [`large_futures`](https://rust-lang.github.io/rust-clippy/master/index.html#large_futures) -## `disallowed-types` -The list of disallowed types, written as fully qualified paths. +## `ignore-interior-mutability` +A list of paths to types that should be treated like `Arc`, i.e. ignored but +for the generic parameters for determining interior mutability -**Default Value:** `[]` +**Default Value:** `["bytes::Bytes"]` --- **Affected lints:** -* [`disallowed_types`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types) +* [`ifs_same_cond`](https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond) +* [`mutable_key_type`](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type) -## `unreadable-literal-lint-fractions` -Should the fraction of a decimal be linted to include separators. +## `large-error-threshold` +The maximum size of the `Err`-variant in a `Result` returned from a function -**Default Value:** `true` +**Default Value:** `128` --- **Affected lints:** -* [`unreadable_literal`](https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal) +* [`result_large_err`](https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err) -## `upper-case-acronyms-aggressive` -Enables verbose mode. Triggers if there is more than one uppercase char next to each other +## `literal-representation-threshold` +The lower bound for linting decimal literals -**Default Value:** `false` +**Default Value:** `16384` --- **Affected lints:** -* [`upper_case_acronyms`](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms) +* [`decimal_literal_representation`](https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation) ## `matches-for-let-else` @@ -472,163 +522,219 @@ be filtering for common types. * [`manual_let_else`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else) -## `cargo-ignore-publish` -For internal testing only, ignores the current `publish` settings in the Cargo manifest. +## `max-fn-params-bools` +The maximum number of bool parameters a function can have -**Default Value:** `false` +**Default Value:** `3` --- **Affected lints:** -* [`cargo_common_metadata`](https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata) - +* [`fn_params_excessive_bools`](https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools) -## `standard-macro-braces` -Enforce the named macros always use the braces specified. -A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro -could be used with a full path two `MacroMatcher`s have to be added one with the full path -`crate_name::macro_name` and one with just the macro name. +## `max-include-file-size` +The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes -**Default Value:** `[]` +**Default Value:** `1000000` --- **Affected lints:** -* [`nonstandard_macro_braces`](https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces) +* [`large_include_file`](https://rust-lang.github.io/rust-clippy/master/index.html#large_include_file) -## `enforced-import-renames` -The list of imports to always rename, a fully qualified path followed by the rename. +## `max-struct-bools` +The maximum number of bool fields a struct can have -**Default Value:** `[]` +**Default Value:** `3` --- **Affected lints:** -* [`missing_enforced_import_renames`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames) +* [`struct_excessive_bools`](https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools) -## `allowed-scripts` -The list of unicode scripts allowed to be used in the scope. +## `max-suggested-slice-pattern-length` +When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in +the slice pattern that is suggested. If more elements are necessary, the lint is suppressed. +For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. -**Default Value:** `["Latin"]` +**Default Value:** `3` --- **Affected lints:** -* [`disallowed_script_idents`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents) +* [`index_refutable_slice`](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice) -## `enable-raw-pointer-heuristic-for-send` -Whether to apply the raw pointer heuristic to determine if a type is `Send`. +## `max-trait-bounds` +The maximum number of bounds a trait can have to be linted -**Default Value:** `true` +**Default Value:** `3` --- **Affected lints:** -* [`non_send_fields_in_send_ty`](https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty) +* [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds) -## `max-suggested-slice-pattern-length` -When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in -the slice pattern that is suggested. If more elements are necessary, the lint is suppressed. -For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. +## `min-ident-chars-threshold` +Minimum chars an ident can have, anything below or equal to this will be linted. -**Default Value:** `3` +**Default Value:** `1` --- **Affected lints:** -* [`index_refutable_slice`](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice) +* [`min_ident_chars`](https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars) -## `await-holding-invalid-types` +## `missing-docs-in-crate-items` +Whether to **only** check for missing documentation in items visible within the current +crate. For example, `pub(crate)` items. +**Default Value:** `false` -**Default Value:** `[]` +--- +**Affected lints:** +* [`missing_docs_in_private_items`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items) + + +## `msrv` +The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml` --- **Affected lints:** -* [`await_holding_invalid_type`](https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_invalid_type) +* [`almost_complete_range`](https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range) +* [`approx_constant`](https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant) +* [`borrow_as_ptr`](https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr) +* [`cast_abs_to_unsigned`](https://rust-lang.github.io/rust-clippy/master/index.html#cast_abs_to_unsigned) +* [`checked_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions) +* [`cloned_instead_of_copied`](https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied) +* [`collapsible_str_replace`](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_str_replace) +* [`deprecated_cfg_attr`](https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr) +* [`derivable_impls`](https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls) +* [`err_expect`](https://rust-lang.github.io/rust-clippy/master/index.html#err_expect) +* [`filter_map_next`](https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next) +* [`from_over_into`](https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into) +* [`if_then_some_else_none`](https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none) +* [`index_refutable_slice`](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice) +* [`iter_kv_map`](https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map) +* [`manual_bits`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits) +* [`manual_c_str_literals`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals) +* [`manual_clamp`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp) +* [`manual_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one) +* [`manual_is_ascii_check`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check) +* [`manual_let_else`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else) +* [`manual_non_exhaustive`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive) +* [`manual_range_contains`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains) +* [`manual_rem_euclid`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid) +* [`manual_retain`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain) +* [`manual_split_once`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once) +* [`manual_str_repeat`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat) +* [`manual_strip`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip) +* [`manual_try_fold`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold) +* [`map_clone`](https://rust-lang.github.io/rust-clippy/master/index.html#map_clone) +* [`map_unwrap_or`](https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or) +* [`match_like_matches_macro`](https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro) +* [`mem_replace_with_default`](https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default) +* [`missing_const_for_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn) +* [`needless_borrow`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow) +* [`option_as_ref_deref`](https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref) +* [`option_map_unwrap_or`](https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or) +* [`ptr_as_ptr`](https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr) +* [`redundant_field_names`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names) +* [`redundant_static_lifetimes`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes) +* [`seek_from_current`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current) +* [`seek_rewind`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_rewind) +* [`transmute_ptr_to_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref) +* [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions) +* [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds) +* [`unchecked_duration_subtraction`](https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction) +* [`uninlined_format_args`](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args) +* [`unnecessary_lazy_evaluations`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations) +* [`unnested_or_patterns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns) +* [`use_self`](https://rust-lang.github.io/rust-clippy/master/index.html#use_self) -## `max-include-file-size` -The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes +## `pass-by-value-size-limit` +The minimum size (in bytes) to consider a type for passing by reference instead of by value. -**Default Value:** `1000000` +**Default Value:** `256` --- **Affected lints:** -* [`large_include_file`](https://rust-lang.github.io/rust-clippy/master/index.html#large_include_file) +* [`large_types_passed_by_value`](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value) -## `allow-expect-in-tests` -Whether `expect` should be allowed in test functions or `#[cfg(test)]` +## `pub-underscore-fields-behavior` +Lint "public" fields in a struct that are prefixed with an underscore based on their +exported visibility, or whether they are marked as "pub". -**Default Value:** `false` +**Default Value:** `"PubliclyExported"` --- **Affected lints:** -* [`expect_used`](https://rust-lang.github.io/rust-clippy/master/index.html#expect_used) +* [`pub_underscore_fields`](https://rust-lang.github.io/rust-clippy/master/index.html#pub_underscore_fields) -## `allow-unwrap-in-tests` -Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` +## `semicolon-inside-block-ignore-singleline` +Whether to lint only if it's multiline. **Default Value:** `false` --- **Affected lints:** -* [`unwrap_used`](https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used) +* [`semicolon_inside_block`](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_inside_block) -## `allow-dbg-in-tests` -Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` +## `semicolon-outside-block-ignore-multiline` +Whether to lint only if it's singleline. **Default Value:** `false` --- **Affected lints:** -* [`dbg_macro`](https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro) +* [`semicolon_outside_block`](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block) -## `allow-print-in-tests` -Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]` +## `single-char-binding-names-threshold` +The maximum number of single char bindings a scope may have -**Default Value:** `false` +**Default Value:** `4` --- **Affected lints:** -* [`print_stdout`](https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout) -* [`print_stderr`](https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr) +* [`many_single_char_names`](https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names) -## `large-error-threshold` -The maximum size of the `Err`-variant in a `Result` returned from a function +## `stack-size-threshold` +The maximum allowed stack size for functions in bytes -**Default Value:** `128` +**Default Value:** `512000` --- **Affected lints:** -* [`result_large_err`](https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err) +* [`large_stack_frames`](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_frames) -## `ignore-interior-mutability` -A list of paths to types that should be treated like `Arc`, i.e. ignored but -for the generic parameters for determining interior mutability +## `standard-macro-braces` +Enforce the named macros always use the braces specified. -**Default Value:** `["bytes::Bytes"]` +A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro +could be used with a full path two `MacroMatcher`s have to be added one with the full path +`crate_name::macro_name` and one with just the macro name. + +**Default Value:** `[]` --- **Affected lints:** -* [`mutable_key_type`](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type) -* [`ifs_same_cond`](https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond) +* [`nonstandard_macro_braces`](https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces) -## `allow-mixed-uninlined-format-args` -Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` +## `struct-field-name-threshold` +The minimum number of struct fields for the lints about field names to trigger -**Default Value:** `true` +**Default Value:** `3` --- **Affected lints:** -* [`uninlined_format_args`](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args) +* [`struct_field_names`](https://rust-lang.github.io/rust-clippy/master/index.html#struct_field_names) ## `suppress-restriction-lint-in-const` @@ -645,217 +751,111 @@ if no suggestion can be made. * [`indexing_slicing`](https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing) -## `missing-docs-in-crate-items` -Whether to **only** check for missing documentation in items visible within the current -crate. For example, `pub(crate)` items. - -**Default Value:** `false` - ---- -**Affected lints:** -* [`missing_docs_in_private_items`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items) - - -## `future-size-threshold` -The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint +## `too-large-for-stack` +The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap -**Default Value:** `16384` +**Default Value:** `200` --- **Affected lints:** -* [`large_futures`](https://rust-lang.github.io/rust-clippy/master/index.html#large_futures) +* [`boxed_local`](https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local) +* [`useless_vec`](https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec) -## `unnecessary-box-size` -The byte size a `T` in `Box` can have, below which it triggers the `clippy::unnecessary_box` lint +## `too-many-arguments-threshold` +The maximum number of argument a function or method can have -**Default Value:** `128` +**Default Value:** `7` --- **Affected lints:** -* [`unnecessary_box_returns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns) +* [`too_many_arguments`](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments) -## `allow-private-module-inception` -Whether to allow module inception if it's not public. +## `too-many-lines-threshold` +The maximum number of lines a function or method can have -**Default Value:** `false` +**Default Value:** `100` --- **Affected lints:** -* [`module_inception`](https://rust-lang.github.io/rust-clippy/master/index.html#module_inception) - +* [`too_many_lines`](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines) -## `allowed-idents-below-min-chars` -Allowed names below the minimum allowed characters. The value `".."` can be used as part of -the list to indicate, that the configured values should be appended to the default -configuration of Clippy. By default, any configuration will replace the default value. -**Default Value:** `["j", "z", "i", "y", "n", "x", "w"]` +## `trivial-copy-size-limit` +The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by +reference. By default there is no limit --- **Affected lints:** -* [`min_ident_chars`](https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars) +* [`trivially_copy_pass_by_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref) -## `min-ident-chars-threshold` -Minimum chars an ident can have, anything below or equal to this will be linted. +## `type-complexity-threshold` +The maximum complexity a type can have -**Default Value:** `1` +**Default Value:** `250` --- **Affected lints:** -* [`min_ident_chars`](https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars) +* [`type_complexity`](https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity) -## `accept-comment-above-statement` -Whether to accept a safety comment to be placed above the statement containing the `unsafe` block +## `unnecessary-box-size` +The byte size a `T` in `Box` can have, below which it triggers the `clippy::unnecessary_box` lint -**Default Value:** `true` +**Default Value:** `128` --- **Affected lints:** -* [`undocumented_unsafe_blocks`](https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks) +* [`unnecessary_box_returns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns) -## `accept-comment-above-attributes` -Whether to accept a safety comment to be placed above the attributes for the `unsafe` block +## `unreadable-literal-lint-fractions` +Should the fraction of a decimal be linted to include separators. **Default Value:** `true` --- **Affected lints:** -* [`undocumented_unsafe_blocks`](https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks) +* [`unreadable_literal`](https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal) -## `allow-one-hash-in-raw-strings` -Whether to allow `r#""#` when `r""` can be used +## `upper-case-acronyms-aggressive` +Enables verbose mode. Triggers if there is more than one uppercase char next to each other **Default Value:** `false` --- **Affected lints:** -* [`unnecessary_raw_string_hashes`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_raw_string_hashes) - - -## `absolute-paths-max-segments` -The maximum number of segments a path can have before being linted, anything above this will -be linted. - -**Default Value:** `2` - ---- -**Affected lints:** -* [`absolute_paths`](https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths) - - -## `absolute-paths-allowed-crates` -Which crates to allow absolute paths from - -**Default Value:** `[]` - ---- -**Affected lints:** -* [`absolute_paths`](https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths) - - -## `allowed-dotfiles` -Additional dotfiles (files or directories starting with a dot) to allow - -**Default Value:** `[]` - ---- -**Affected lints:** -* [`path_ends_with_ext`](https://rust-lang.github.io/rust-clippy/master/index.html#path_ends_with_ext) +* [`upper_case_acronyms`](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms) -## `allowed-duplicate-crates` -A list of crate names to allow duplicates of +## `vec-box-size-threshold` +The size of the boxed type in bytes, where boxing in a `Vec` is allowed -**Default Value:** `[]` +**Default Value:** `4096` --- **Affected lints:** -* [`multiple_crate_versions`](https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions) - - -## `enforce-iter-loop-reborrow` -Whether to recommend using implicit into iter for reborrowed values. +* [`vec_box`](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box) -#### Example -```no_run -let mut vec = vec![1, 2, 3]; -let rmvec = &mut vec; -for _ in rmvec.iter() {} -for _ in rmvec.iter_mut() {} -``` -Use instead: -```no_run -let mut vec = vec![1, 2, 3]; -let rmvec = &mut vec; -for _ in &*rmvec {} -for _ in &mut *rmvec {} -``` +## `verbose-bit-mask-threshold` +The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros' -**Default Value:** `false` +**Default Value:** `1` --- **Affected lints:** -* [`explicit_iter_loop`](https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop) +* [`verbose_bit_mask`](https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask) -## `check-private-items` -Whether to also run the listed lints on private items. +## `warn-on-all-wildcard-imports` +Whether to allow certain wildcard imports (prelude, super in tests). **Default Value:** `false` ---- -**Affected lints:** -* [`missing_safety_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc) -* [`unnecessary_safety_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_doc) -* [`missing_panics_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc) -* [`missing_errors_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc) - - -## `pub-underscore-fields-behavior` -Lint "public" fields in a struct that are prefixed with an underscore based on their -exported visibility, or whether they are marked as "pub". - -**Default Value:** `"PubliclyExported"` - ---- -**Affected lints:** -* [`pub_underscore_fields`](https://rust-lang.github.io/rust-clippy/master/index.html#pub_underscore_fields) - - -## `allow-comparison-to-zero` -Don't lint when comparing the result of a modulo operation to zero. - -**Default Value:** `true` - ---- -**Affected lints:** -* [`modulo_arithmetic`](https://rust-lang.github.io/rust-clippy/master/index.html#modulo_arithmetic) - - -## `allowed-wildcard-imports` -List of path segments allowed to have wildcard imports. - -#### Example - -```toml -allowed-wildcard-imports = [ "utils", "common" ] -``` - -#### Noteworthy - -1. This configuration has no effects if used with `warn_on_all_wildcard_imports = true`. -2. Paths with any segment that containing the word 'prelude' -are already allowed by default. - -**Default Value:** `[]` - --- **Affected lints:** * [`wildcard_imports`](https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index b781259ad9695..673b6328b3901 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -193,7 +193,7 @@ macro_rules! define_Conf { } pub fn get_configuration_metadata() -> Vec { - vec![ + let mut sorted = vec![ $( { let deprecation_reason = wrap_option!($($dep)?); @@ -206,7 +206,9 @@ macro_rules! define_Conf { ) }, )+ - ] + ]; + sorted.sort_by(|a, b| a.name.cmp(&b.name)); + sorted } }; } diff --git a/clippy_config/src/metadata.rs b/clippy_config/src/metadata.rs index 3ba2796e18d3c..400887185e8cf 100644 --- a/clippy_config/src/metadata.rs +++ b/clippy_config/src/metadata.rs @@ -26,9 +26,11 @@ impl ClippyConfiguration { doc_comment: &'static str, deprecation_reason: Option<&'static str>, ) -> Self { - let (lints, doc) = parse_config_field_doc(doc_comment) + let (mut lints, doc) = parse_config_field_doc(doc_comment) .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string())); + lints.sort(); + Self { name: to_kebab(name), lints, From d013b5a4620cffc1643bf540b0bad3a1d1a63991 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Fri, 12 Jan 2024 14:22:06 +0100 Subject: [PATCH 005/137] Stabilize the `#[diagnostic]` namespace and `#[diagnostic::on_unimplemented]` attribute This PR stabilizes the `#[diagnostic]` attribute namespace and a minimal option of the `#[diagnostic::on_unimplemented]` attribute. The `#[diagnostic]` attribute namespace is meant to provide a home for attributes that allow users to influence error messages emitted by the compiler. The compiler is not guaranteed to use any of this hints, however it should accept any (non-)existing attribute in this namespace and potentially emit lint-warnings for unused attributes and options. This is meant to allow discarding certain attributes/options in the future to allow fundamental changes to the compiler without the need to keep then non-meaningful options working. The `#[diagnostic::on_unimplemented]` attribute is allowed to appear on a trait definition. This allows crate authors to hint the compiler to emit a specific error message if a certain trait is not implemented. For the `#[diagnostic::on_unimplemented]` attribute the following options are implemented: * `message` which provides the text for the top level error message * `label` which provides the text for the label shown inline in the broken code in the error message * `note` which provides additional notes. The `note` option can appear several times, which results in several note messages being emitted. If any of the other options appears several times the first occurrence of the relevant option specifies the actually used value. Any other occurrence generates an lint warning. For any other non-existing option a lint-warning is generated. All three options accept a text as argument. This text is allowed to contain format parameters referring to generic argument or `Self` by name via the `{Self}` or `{NameOfGenericArgument}` syntax. For any non-existing argument a lint warning is generated. Tracking issue: #111996 --- compiler/rustc_ast_passes/src/feature_gate.rs | 8 -- compiler/rustc_feature/src/accepted.rs | 2 + compiler/rustc_feature/src/unstable.rs | 2 - library/core/src/lib.rs | 2 +- .../language-features/diagnostic-namespace.md | 84 ------------------- .../existing_proc_macros.rs | 1 - .../feature-gate-diagnostic_namespace.rs | 13 --- .../feature-gate-diagnostic_namespace.stderr | 37 -------- .../non_existing_attributes_accepted.rs | 1 - .../non_existing_attributes_accepted.stderr | 4 +- .../on_unimplemented/auxiliary/other.rs | 2 - ...options_of_the_internal_rustc_attribute.rs | 2 - ...ons_of_the_internal_rustc_attribute.stderr | 74 ++++++++-------- ...o_not_fail_parsing_on_invalid_options_1.rs | 2 - ...t_fail_parsing_on_invalid_options_1.stderr | 54 ++++++------ ...eature-gate-diagnostic_on_unimplemented.rs | 7 -- ...re-gate-diagnostic_on_unimplemented.stderr | 13 --- ...ed_options_and_continue_to_use_fallback.rs | 2 - ...ptions_and_continue_to_use_fallback.stderr | 14 ++-- .../on_unimplemented/multiple_notes.rs | 2 - .../on_unimplemented/multiple_notes.stderr | 12 +-- .../on_unimplemented_simple.rs | 2 - .../on_unimplemented_simple.stderr | 6 +- .../report_warning_on_duplicated_options.rs | 2 - ...eport_warning_on_duplicated_options.stderr | 14 ++-- .../ui/diagnostic_namespace/requires_path.rs | 2 - .../diagnostic_namespace/requires_path.stderr | 2 +- 27 files changed, 93 insertions(+), 273 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/diagnostic-namespace.md delete mode 100644 tests/ui/diagnostic_namespace/feature-gate-diagnostic_namespace.rs delete mode 100644 tests/ui/diagnostic_namespace/feature-gate-diagnostic_namespace.stderr delete mode 100644 tests/ui/diagnostic_namespace/on_unimplemented/feature-gate-diagnostic_on_unimplemented.rs delete mode 100644 tests/ui/diagnostic_namespace/on_unimplemented/feature-gate-diagnostic_on_unimplemented.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 1b0dd9acc3782..7dd1c35f7d685 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -203,14 +203,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ); } } - if !attr.is_doc_comment() - && let [seg, _] = attr.get_normal_item().path.segments.as_slice() - && seg.ident.name == sym::diagnostic - && !self.features.diagnostic_namespace - { - let msg = "`#[diagnostic]` attribute name space is experimental"; - gate!(self, diagnostic_namespace, seg.ident.span, msg); - } // Emit errors for non-staged-api crates. if !self.features.staged_api { diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 1b2993dabdb83..7e5197f16f91e 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -146,6 +146,8 @@ declare_features! ( (accepted, derive_default_enum, "1.62.0", Some(86985)), /// Allows the use of destructuring assignments. (accepted, destructuring_assignment, "1.59.0", Some(71126)), + /// Allows using the `#[diagnostic]` attribute tool namespace + (accepted, diagnostic_namespace, "CURRENT_RUSTC_VERSION", Some(111996)), /// Allows `#[doc(alias = "...")]`. (accepted, doc_alias, "1.48.0", Some(50146)), /// Allows `..` in tuple (struct) patterns. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 53254d567ccf2..19ad38b6e9f57 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -434,8 +434,6 @@ declare_features! ( (unstable, deprecated_safe, "1.61.0", Some(94978)), /// Allows having using `suggestion` in the `#[deprecated]` attribute. (unstable, deprecated_suggestion, "1.61.0", Some(94785)), - /// Allows using the `#[diagnostic]` attribute tool namespace - (unstable, diagnostic_namespace, "1.73.0", Some(111996)), /// Controls errors in trait implementations. (unstable, do_not_recommend, "1.67.0", Some(51992)), /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 7b735d48bdfce..0f7885769c267 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -202,6 +202,7 @@ // // Language features: // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(diagnostic_namespace))] #![cfg_attr(bootstrap, feature(platform_intrinsics))] #![feature(abi_unadjusted)] #![feature(adt_const_params)] @@ -223,7 +224,6 @@ #![feature(const_trait_impl)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] -#![feature(diagnostic_namespace)] #![feature(doc_cfg)] #![feature(doc_cfg_hide)] #![feature(doc_notable_trait)] diff --git a/src/doc/unstable-book/src/language-features/diagnostic-namespace.md b/src/doc/unstable-book/src/language-features/diagnostic-namespace.md deleted file mode 100644 index 7c46811a27ab8..0000000000000 --- a/src/doc/unstable-book/src/language-features/diagnostic-namespace.md +++ /dev/null @@ -1,84 +0,0 @@ -# `diagnostic_namespace` - -The tracking issue for this feature is: [#111996] - -[#111996]: https://github.com/rust-lang/rust/issues/111996 - ------------------------- - -The `diagnostic_namespace` feature permits customization of compilation errors. - -## diagnostic::on_unimplemented - -With [#114452] support for `diagnostic::on_unimplemented` was added. - -When used on a trait declaration, the following options are available: - -* `message` to customize the primary error message -* `note` to add a customized note message to an error message -* `label` to customize the label part of the error message - -The attribute will hint to the compiler to use these in error messages: -```rust -// some library -#![feature(diagnostic_namespace)] - -#[diagnostic::on_unimplemented( - message = "cannot insert element", - label = "cannot be put into a table", - note = "see for more information about the Table api" -)] -pub trait Element { - // ... -} -``` - -```rust,compile_fail,E0277 -# #![feature(diagnostic_namespace)] -# -# #[diagnostic::on_unimplemented( -# message = "cannot insert element", -# label = "cannot be put into a table", -# note = "see for more information about the Table api" -# )] -# pub trait Element { -# // ... -# } -# struct Table; -# impl Table { -# fn insert(&self, element: T) { -# // .. -# } -# } -# fn main() { -# let table = Table; -# let element = (); -// user code -table.insert(element); -# } -``` - -```text -error[E0277]: cannot insert element - --> src/main.rs:24:18 - | -24 | table.insert(element); - | ------ ^^^^^^^ cannot be put into a table - | | - | required by a bound introduced by this call - | - = help: the trait `Element` is not implemented for `` - = note: see for more information about the Table api -note: required by a bound in `Table::insert` - --> src/main.rs:15:18 - | -15 | fn insert(&self, element: T) { - | ^^^^^^^ required by this bound in `Table::insert` - -For more information about this error, try `rustc --explain E0277`. -``` - -See [RFC 3368] for more information. - -[#114452]: https://github.com/rust-lang/rust/pull/114452 -[RFC 3368]: https://github.com/rust-lang/rfcs/blob/master/text/3368-diagnostic-attribute-namespace.md diff --git a/tests/ui/diagnostic_namespace/existing_proc_macros.rs b/tests/ui/diagnostic_namespace/existing_proc_macros.rs index 2bc58aea8fc2c..014ec46f1b981 100644 --- a/tests/ui/diagnostic_namespace/existing_proc_macros.rs +++ b/tests/ui/diagnostic_namespace/existing_proc_macros.rs @@ -1,4 +1,3 @@ -#![feature(diagnostic_namespace)] //@ check-pass //@ aux-build:proc-macro-helper.rs diff --git a/tests/ui/diagnostic_namespace/feature-gate-diagnostic_namespace.rs b/tests/ui/diagnostic_namespace/feature-gate-diagnostic_namespace.rs deleted file mode 100644 index b08e291621fdc..0000000000000 --- a/tests/ui/diagnostic_namespace/feature-gate-diagnostic_namespace.rs +++ /dev/null @@ -1,13 +0,0 @@ -#[diagnostic::non_existing_attribute] -//~^ERROR `#[diagnostic]` attribute name space is experimental [E0658] -//~|WARNING unknown diagnostic attribute [unknown_or_malformed_diagnostic_attributes] -pub trait Bar { -} - -#[diagnostic::non_existing_attribute(with_option = "foo")] -//~^ERROR `#[diagnostic]` attribute name space is experimental [E0658] -//~|WARNING unknown diagnostic attribute [unknown_or_malformed_diagnostic_attributes] -struct Foo; - -fn main() { -} diff --git a/tests/ui/diagnostic_namespace/feature-gate-diagnostic_namespace.stderr b/tests/ui/diagnostic_namespace/feature-gate-diagnostic_namespace.stderr deleted file mode 100644 index 38424c13d8613..0000000000000 --- a/tests/ui/diagnostic_namespace/feature-gate-diagnostic_namespace.stderr +++ /dev/null @@ -1,37 +0,0 @@ -error[E0658]: `#[diagnostic]` attribute name space is experimental - --> $DIR/feature-gate-diagnostic_namespace.rs:1:3 - | -LL | #[diagnostic::non_existing_attribute] - | ^^^^^^^^^^ - | - = note: see issue #111996 for more information - = help: add `#![feature(diagnostic_namespace)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: `#[diagnostic]` attribute name space is experimental - --> $DIR/feature-gate-diagnostic_namespace.rs:7:3 - | -LL | #[diagnostic::non_existing_attribute(with_option = "foo")] - | ^^^^^^^^^^ - | - = note: see issue #111996 for more information - = help: add `#![feature(diagnostic_namespace)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -warning: unknown diagnostic attribute - --> $DIR/feature-gate-diagnostic_namespace.rs:1:15 - | -LL | #[diagnostic::non_existing_attribute] - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default - -warning: unknown diagnostic attribute - --> $DIR/feature-gate-diagnostic_namespace.rs:7:15 - | -LL | #[diagnostic::non_existing_attribute(with_option = "foo")] - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors; 2 warnings emitted - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.rs b/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.rs index 95465701bf858..f6957b1448d18 100644 --- a/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.rs +++ b/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.rs @@ -1,4 +1,3 @@ -#![feature(diagnostic_namespace)] //@ check-pass #[diagnostic::non_existing_attribute] //~^WARN unknown diagnostic attribute diff --git a/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr b/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr index 753077b365e8f..c073ec9b103f6 100644 --- a/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr +++ b/tests/ui/diagnostic_namespace/non_existing_attributes_accepted.stderr @@ -1,5 +1,5 @@ warning: unknown diagnostic attribute - --> $DIR/non_existing_attributes_accepted.rs:3:15 + --> $DIR/non_existing_attributes_accepted.rs:2:15 | LL | #[diagnostic::non_existing_attribute] | ^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[diagnostic::non_existing_attribute] = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: unknown diagnostic attribute - --> $DIR/non_existing_attributes_accepted.rs:8:15 + --> $DIR/non_existing_attributes_accepted.rs:7:15 | LL | #[diagnostic::non_existing_attribute(with_option = "foo")] | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/auxiliary/other.rs b/tests/ui/diagnostic_namespace/on_unimplemented/auxiliary/other.rs index 884bab2800a5b..512ef6330e5ec 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/auxiliary/other.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/auxiliary/other.rs @@ -1,5 +1,3 @@ -#![feature(diagnostic_namespace)] - #[diagnostic::on_unimplemented( message = "Message", note = "Note", diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs index eb985c062f3dd..30a85ff21992d 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs @@ -1,5 +1,3 @@ -#![feature(diagnostic_namespace)] - #[diagnostic::on_unimplemented( on(_Self = "&str"), //~^WARN malformed `on_unimplemented` attribute diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr index 75a701f0b5f65..e34b917f67e10 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr @@ -1,5 +1,5 @@ warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definitions - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:24:1 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:22:1 | LL | #[diagnostic::on_unimplemented(message = "Not allowed to apply it on a impl")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[diagnostic::on_unimplemented(message = "Not allowed to apply it on a impl = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:4:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:2:5 | LL | on(_Self = "&str"), | ^^^^^^^^^^^^^^^^^^ invalid option found here @@ -15,7 +15,7 @@ LL | on(_Self = "&str"), = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:10:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:8:5 | LL | parent_label = "in this scope", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -23,7 +23,7 @@ LL | parent_label = "in this scope", = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:13:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:11:5 | LL | append_const_msg | ^^^^^^^^^^^^^^^^ invalid option found here @@ -31,7 +31,7 @@ LL | append_const_msg = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:19:32 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:17:32 | LL | #[diagnostic::on_unimplemented = "Message"] | ^^^^^^^^^^^ invalid option found here @@ -39,7 +39,7 @@ LL | #[diagnostic::on_unimplemented = "Message"] = help: only `message`, `note` and `label` are allowed as options warning: there is no parameter `from_desugaring` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:31:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -47,7 +47,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `direct` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:31:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `cause` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:31:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `integral` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:31:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `integer` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:31:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `float` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:42:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -87,7 +87,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `_Self` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:42:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -95,7 +95,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `crate_local` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:42:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -103,7 +103,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `Trait` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:42:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -111,7 +111,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = help: expect either a generic argument name or `{Self}` as format argument warning: there is no parameter `ItemContext` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:42:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -119,7 +119,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = help: expect either a generic argument name or `{Self}` as format argument warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:4:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:2:5 | LL | on(_Self = "&str"), | ^^^^^^^^^^^^^^^^^^ invalid option found here @@ -128,7 +128,7 @@ LL | on(_Self = "&str"), = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:10:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:8:5 | LL | parent_label = "in this scope", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -137,7 +137,7 @@ LL | parent_label = "in this scope", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:13:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:11:5 | LL | append_const_msg | ^^^^^^^^^^^^^^^^ invalid option found here @@ -146,7 +146,7 @@ LL | append_const_msg = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: trait has `()` and `i32` as params - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:61:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:59:15 | LL | takes_foo(()); | --------- ^^ trait has `()` and `i32` as params @@ -156,18 +156,18 @@ LL | takes_foo(()); = help: the trait `Foo` is not implemented for `()` = note: trait has `()` and `i32` as params help: this trait has no implementations, consider adding one - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:17:1 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:15:1 | LL | trait Foo {} | ^^^^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:56:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:54:22 | LL | fn takes_foo(_: impl Foo) {} | ^^^^^^^^ required by this bound in `takes_foo` warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:19:32 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:17:32 | LL | #[diagnostic::on_unimplemented = "Message"] | ^^^^^^^^^^^ invalid option found here @@ -176,7 +176,7 @@ LL | #[diagnostic::on_unimplemented = "Message"] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `(): Bar` is not satisfied - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:63:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:61:15 | LL | takes_bar(()); | --------- ^^ the trait `Bar` is not implemented for `()` @@ -185,13 +185,13 @@ LL | takes_bar(()); | = help: the trait `Bar` is implemented for `i32` note: required by a bound in `takes_bar` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:57:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:55:22 | LL | fn takes_bar(_: impl Bar) {} | ^^^ required by this bound in `takes_bar` warning: there is no parameter `from_desugaring` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:31:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -200,7 +200,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `direct` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:31:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -209,7 +209,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `cause` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:31:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -218,7 +218,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `integral` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:31:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -227,7 +227,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `integer` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:31:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:29:5 | LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -236,7 +236,7 @@ LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `float` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:42:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -245,7 +245,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `_Self` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:42:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -254,7 +254,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `crate_local` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:42:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -263,7 +263,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `Trait` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:42:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -272,7 +272,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: there is no parameter `ItemContext` on trait `Baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:42:5 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:40:5 | LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -281,7 +281,7 @@ LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}" = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: {from_desugaring}{direct}{cause}{integral}{integer} - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:65:15 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:63:15 | LL | takes_baz(()); | --------- ^^ {float}{_Self}{crate_local}{Trait}{ItemContext} @@ -290,12 +290,12 @@ LL | takes_baz(()); | = help: the trait `Baz` is not implemented for `()` help: this trait has no implementations, consider adding one - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:54:1 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:52:1 | LL | trait Baz {} | ^^^^^^^^^ note: required by a bound in `takes_baz` - --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:58:22 + --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:56:22 | LL | fn takes_baz(_: impl Baz) {} | ^^^ required by this bound in `takes_baz` diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs index 12fe988170ac1..b4234066bb19a 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs @@ -1,5 +1,3 @@ -#![feature(diagnostic_namespace)] - #[diagnostic::on_unimplemented(unsupported = "foo")] //~^WARN malformed `on_unimplemented` attribute //~|WARN malformed `on_unimplemented` attribute diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr index 11263580b15e2..dc0c194823696 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr @@ -1,5 +1,5 @@ warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definitions - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:8:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:6:1 | LL | #[diagnostic::on_unimplemented(message = "Baz")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[diagnostic::on_unimplemented(message = "Baz")] = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:1:32 | LL | #[diagnostic::on_unimplemented(unsupported = "foo")] | ^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -15,7 +15,7 @@ LL | #[diagnostic::on_unimplemented(unsupported = "foo")] = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:10:50 | LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")] | ^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -23,7 +23,7 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")] = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:15:50 | LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -31,7 +31,7 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:32 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:20:32 | LL | #[diagnostic::on_unimplemented = "boom"] | ^^^^^^^^ invalid option found here @@ -39,7 +39,7 @@ LL | #[diagnostic::on_unimplemented = "boom"] = help: only `message`, `note` and `label` are allowed as options warning: missing options for `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:24:1 | LL | #[diagnostic::on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -47,7 +47,7 @@ LL | #[diagnostic::on_unimplemented] = help: at least one of the `message`, `note` and `label` options are expected warning: there is no parameter `DoesNotExist` on trait `Test` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:32 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:29:32 | LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] = help: expect either a generic argument name or `{Self}` as format argument warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:1:32 | LL | #[diagnostic::on_unimplemented(unsupported = "foo")] | ^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -64,7 +64,7 @@ LL | #[diagnostic::on_unimplemented(unsupported = "foo")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `i32: Foo` is not satisfied - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:43:14 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:41:14 | LL | take_foo(1_i32); | -------- ^^^^^ the trait `Foo` is not implemented for `i32` @@ -72,18 +72,18 @@ LL | take_foo(1_i32); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:6:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:4:1 | LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `take_foo` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:36:21 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:34:21 | LL | fn take_foo(_: impl Foo) {} | ^^^ required by this bound in `take_foo` warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:10:50 | LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")] | ^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -92,7 +92,7 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Boom - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:45:14 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:43:14 | LL | take_baz(1_i32); | -------- ^^^^^ the trait `Baz` is not implemented for `i32` @@ -100,18 +100,18 @@ LL | take_baz(1_i32); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:15:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:13:1 | LL | trait Baz {} | ^^^^^^^^^ note: required by a bound in `take_baz` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:37:21 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:35:21 | LL | fn take_baz(_: impl Baz) {} | ^^^ required by this bound in `take_baz` warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:15:50 | LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here @@ -120,7 +120,7 @@ LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Boom - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:47:15 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:45:15 | LL | take_boom(1_i32); | --------- ^^^^^ the trait `Boom` is not implemented for `i32` @@ -128,18 +128,18 @@ LL | take_boom(1_i32); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:20:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:18:1 | LL | trait Boom {} | ^^^^^^^^^^ note: required by a bound in `take_boom` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:38:22 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:36:22 | LL | fn take_boom(_: impl Boom) {} | ^^^^ required by this bound in `take_boom` warning: missing options for `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:24:1 | LL | #[diagnostic::on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -148,7 +148,7 @@ LL | #[diagnostic::on_unimplemented] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `i32: Whatever` is not satisfied - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:49:19 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:47:19 | LL | take_whatever(1_i32); | ------------- ^^^^^ the trait `Whatever` is not implemented for `i32` @@ -156,18 +156,18 @@ LL | take_whatever(1_i32); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:29:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:27:1 | LL | trait Whatever {} | ^^^^^^^^^^^^^^ note: required by a bound in `take_whatever` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:39:26 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:37:26 | LL | fn take_whatever(_: impl Whatever) {} | ^^^^^^^^ required by this bound in `take_whatever` warning: there is no parameter `DoesNotExist` on trait `Test` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:32 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:29:32 | LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -176,7 +176,7 @@ LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: {DoesNotExist} - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:51:15 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:49:15 | LL | take_test(()); | --------- ^^ the trait `Test` is not implemented for `()` @@ -184,12 +184,12 @@ LL | take_test(()); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:34:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:32:1 | LL | trait Test {} | ^^^^^^^^^^ note: required by a bound in `take_test` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:40:22 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:38:22 | LL | fn take_test(_: impl Test) {} | ^^^^ required by this bound in `take_test` diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/feature-gate-diagnostic_on_unimplemented.rs b/tests/ui/diagnostic_namespace/on_unimplemented/feature-gate-diagnostic_on_unimplemented.rs deleted file mode 100644 index 609a840c118c6..0000000000000 --- a/tests/ui/diagnostic_namespace/on_unimplemented/feature-gate-diagnostic_on_unimplemented.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[diagnostic::on_unimplemented(message = "Foo")] -//~^ERROR `#[diagnostic]` attribute name space is experimental [E0658] -pub trait Bar { -} - -fn main() { -} diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/feature-gate-diagnostic_on_unimplemented.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/feature-gate-diagnostic_on_unimplemented.stderr deleted file mode 100644 index 719322fa0f55e..0000000000000 --- a/tests/ui/diagnostic_namespace/on_unimplemented/feature-gate-diagnostic_on_unimplemented.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: `#[diagnostic]` attribute name space is experimental - --> $DIR/feature-gate-diagnostic_on_unimplemented.rs:1:3 - | -LL | #[diagnostic::on_unimplemented(message = "Foo")] - | ^^^^^^^^^^ - | - = note: see issue #111996 for more information - = help: add `#![feature(diagnostic_namespace)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs index 0893f29c4a3b4..5b25fb234bc52 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs @@ -1,5 +1,3 @@ -#![feature(diagnostic_namespace)] - #[diagnostic::on_unimplemented( if(Self = "()"), //~^WARN malformed `on_unimplemented` attribute diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr index e00846da77be5..56d125e20e5c4 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr @@ -1,5 +1,5 @@ warning: malformed `on_unimplemented` attribute - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:4:5 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:2:5 | LL | if(Self = "()"), | ^^^^^^^^^^^^^^^ invalid option found here @@ -8,7 +8,7 @@ LL | if(Self = "()"), = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: `message` is ignored due to previous definition of `message` - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:10:32 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:8:32 | LL | message = "custom message", | -------------------------- `message` is first declared here @@ -17,7 +17,7 @@ LL | #[diagnostic::on_unimplemented(message = "fallback!!")] | ^^^^^^^^^^^^^^^^^^^^^^ `message` is already declared here warning: malformed `on_unimplemented` attribute - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:4:5 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:2:5 | LL | if(Self = "()"), | ^^^^^^^^^^^^^^^ invalid option found here @@ -26,7 +26,7 @@ LL | if(Self = "()"), = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: `message` is ignored due to previous definition of `message` - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:10:32 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:8:32 | LL | message = "custom message", | -------------------------- `message` is first declared here @@ -37,7 +37,7 @@ LL | #[diagnostic::on_unimplemented(message = "fallback!!")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: custom message - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:20:15 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:18:15 | LL | takes_foo(()); | --------- ^^ fallback label @@ -48,12 +48,12 @@ LL | takes_foo(()); = note: custom note = note: fallback note help: this trait has no implementations, consider adding one - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:1 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:13:1 | LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:17:22 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:22 | LL | fn takes_foo(_: impl Foo) {} | ^^^ required by this bound in `takes_foo` diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.rs b/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.rs index 34cdb99c754b1..a5982f6492ca5 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.rs @@ -1,5 +1,3 @@ -#![feature(diagnostic_namespace)] - #[diagnostic::on_unimplemented(message = "Foo", label = "Bar", note = "Baz", note = "Boom")] trait Foo {} diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.stderr index c72321d4617f0..93a0d0b3f4132 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/multiple_notes.stderr @@ -1,5 +1,5 @@ error[E0277]: Foo - --> $DIR/multiple_notes.rs:14:15 + --> $DIR/multiple_notes.rs:12:15 | LL | takes_foo(()); | --------- ^^ Bar @@ -10,18 +10,18 @@ LL | takes_foo(()); = note: Baz = note: Boom help: this trait has no implementations, consider adding one - --> $DIR/multiple_notes.rs:4:1 + --> $DIR/multiple_notes.rs:2:1 | LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/multiple_notes.rs:10:22 + --> $DIR/multiple_notes.rs:8:22 | LL | fn takes_foo(_: impl Foo) {} | ^^^ required by this bound in `takes_foo` error[E0277]: Bar - --> $DIR/multiple_notes.rs:16:15 + --> $DIR/multiple_notes.rs:14:15 | LL | takes_bar(()); | --------- ^^ Foo @@ -32,12 +32,12 @@ LL | takes_bar(()); = note: Baz = note: Baz2 help: this trait has no implementations, consider adding one - --> $DIR/multiple_notes.rs:8:1 + --> $DIR/multiple_notes.rs:6:1 | LL | trait Bar {} | ^^^^^^^^^ note: required by a bound in `takes_bar` - --> $DIR/multiple_notes.rs:11:22 + --> $DIR/multiple_notes.rs:9:22 | LL | fn takes_bar(_: impl Bar) {} | ^^^ required by this bound in `takes_bar` diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs b/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs index 797edbc9ec564..7ca0312775964 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.rs @@ -1,5 +1,3 @@ -#![feature(diagnostic_namespace)] - #[diagnostic::on_unimplemented(message = "Foo", label = "Bar", note = "Baz")] trait Foo {} diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr index de57f7044bffe..6b17f40c6dd16 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/on_unimplemented_simple.stderr @@ -1,5 +1,5 @@ error[E0277]: Foo - --> $DIR/on_unimplemented_simple.rs:9:15 + --> $DIR/on_unimplemented_simple.rs:7:15 | LL | takes_foo(()); | --------- ^^ Bar @@ -9,12 +9,12 @@ LL | takes_foo(()); = help: the trait `Foo` is not implemented for `()` = note: Baz help: this trait has no implementations, consider adding one - --> $DIR/on_unimplemented_simple.rs:4:1 + --> $DIR/on_unimplemented_simple.rs:2:1 | LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/on_unimplemented_simple.rs:6:22 + --> $DIR/on_unimplemented_simple.rs:4:22 | LL | fn takes_foo(_: impl Foo) {} | ^^^ required by this bound in `takes_foo` diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.rs b/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.rs index a7becd2f88f6d..8c0b81504177f 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.rs @@ -1,5 +1,3 @@ -#![feature(diagnostic_namespace)] - #[diagnostic::on_unimplemented( message = "first message", label = "first label", diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr index d30754dcf10d0..43ab6bf25a1a2 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/report_warning_on_duplicated_options.stderr @@ -1,5 +1,5 @@ warning: `message` is ignored due to previous definition of `message` - --> $DIR/report_warning_on_duplicated_options.rs:9:5 + --> $DIR/report_warning_on_duplicated_options.rs:7:5 | LL | message = "first message", | ------------------------- `message` is first declared here @@ -10,7 +10,7 @@ LL | message = "second message", = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: `label` is ignored due to previous definition of `label` - --> $DIR/report_warning_on_duplicated_options.rs:12:5 + --> $DIR/report_warning_on_duplicated_options.rs:10:5 | LL | label = "first label", | --------------------- `label` is first declared here @@ -19,7 +19,7 @@ LL | label = "second label", | ^^^^^^^^^^^^^^^^^^^^^^ `label` is already declared here warning: `message` is ignored due to previous definition of `message` - --> $DIR/report_warning_on_duplicated_options.rs:9:5 + --> $DIR/report_warning_on_duplicated_options.rs:7:5 | LL | message = "first message", | ------------------------- `message` is first declared here @@ -30,7 +30,7 @@ LL | message = "second message", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` warning: `label` is ignored due to previous definition of `label` - --> $DIR/report_warning_on_duplicated_options.rs:12:5 + --> $DIR/report_warning_on_duplicated_options.rs:10:5 | LL | label = "first label", | --------------------- `label` is first declared here @@ -41,7 +41,7 @@ LL | label = "second label", = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: first message - --> $DIR/report_warning_on_duplicated_options.rs:23:15 + --> $DIR/report_warning_on_duplicated_options.rs:21:15 | LL | takes_foo(()); | --------- ^^ first label @@ -52,12 +52,12 @@ LL | takes_foo(()); = note: custom note = note: second note help: this trait has no implementations, consider adding one - --> $DIR/report_warning_on_duplicated_options.rs:17:1 + --> $DIR/report_warning_on_duplicated_options.rs:15:1 | LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/report_warning_on_duplicated_options.rs:20:22 + --> $DIR/report_warning_on_duplicated_options.rs:18:22 | LL | fn takes_foo(_: impl Foo) {} | ^^^ required by this bound in `takes_foo` diff --git a/tests/ui/diagnostic_namespace/requires_path.rs b/tests/ui/diagnostic_namespace/requires_path.rs index e8d6ca73ad0cf..4f3a1319cafff 100644 --- a/tests/ui/diagnostic_namespace/requires_path.rs +++ b/tests/ui/diagnostic_namespace/requires_path.rs @@ -1,5 +1,3 @@ -#![feature(diagnostic_namespace)] - #[diagnostic] //~^ERROR cannot find attribute `diagnostic` in this scope pub struct Bar; diff --git a/tests/ui/diagnostic_namespace/requires_path.stderr b/tests/ui/diagnostic_namespace/requires_path.stderr index 5d07d3a22d50e..e02aacac8c1a7 100644 --- a/tests/ui/diagnostic_namespace/requires_path.stderr +++ b/tests/ui/diagnostic_namespace/requires_path.stderr @@ -1,5 +1,5 @@ error: cannot find attribute `diagnostic` in this scope - --> $DIR/requires_path.rs:3:3 + --> $DIR/requires_path.rs:1:3 | LL | #[diagnostic] | ^^^^^^^^^^ From 03bb7908b964fd461b2ba277dcf4c04608b083ef Mon Sep 17 00:00:00 2001 From: Ethiraric Date: Tue, 27 Feb 2024 11:41:38 +0100 Subject: [PATCH 006/137] [`map_entry`]: Check insert expression for map use The lint makes sure that the map is not used (borrowed) before the call to `insert`. Since the lint creates a mutable borrow on the map with the `Entry`, it wouldn't be possible to replace such code with `Entry`. However, expressions up to the `insert` call are checked, but not expressions for the arguments of the `insert` call itself. This commit fixes that. Fixes #11935 --- clippy_lints/src/entry.rs | 55 +++++++++++++++++++++++++++++++++++++-- tests/ui/entry.fixed | 11 ++++++++ tests/ui/entry.rs | 11 ++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 0b4bc375df0d9..de6073c272360 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -214,12 +214,31 @@ impl MapType { } } +/// Details on an expression checking whether a map contains a key. +/// +/// For instance, with the following: +/// ```ignore +/// !!!self.the_map.contains_key("the_key") +/// ``` +/// +/// - `negated` will be set to `true` (the 3 `!` negate the condition) +/// - `map` will be the `self.the_map` expression +/// - `key` will be the `"the_key"` expression struct ContainsExpr<'tcx> { + /// Whether the check for `contains_key` was negated. negated: bool, + /// The map on which the check is performed. map: &'tcx Expr<'tcx>, + /// The key that is checked to be contained. key: &'tcx Expr<'tcx>, + /// The context of the whole condition expression. call_ctxt: SyntaxContext, } + +/// Inspect the given expression and return details about the `contains_key` check. +/// +/// If the given expression is not a `contains_key` check against a `BTreeMap` or a `HashMap`, +/// return `None`. fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(MapType, ContainsExpr<'tcx>)> { let mut negated = false; let expr = peel_hir_expr_while(expr, |e| match e.kind { @@ -229,6 +248,7 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio }, _ => None, }); + match expr.kind { ExprKind::MethodCall( _, @@ -261,11 +281,28 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio } } +/// Details on an expression inserting a key into a map. +/// +/// For instance, on the following: +/// ```ignore +/// self.the_map.insert("the_key", 3 + 4); +/// ``` +/// +/// - `map` will be the `self.the_map` expression +/// - `key` will be the `"the_key"` expression +/// - `value` will be the `3 + 4` expression struct InsertExpr<'tcx> { + /// The map into which the insertion is performed. map: &'tcx Expr<'tcx>, + /// The key at which to insert. key: &'tcx Expr<'tcx>, + /// The value to insert. value: &'tcx Expr<'tcx>, } + +/// Inspect the given expression and return details about the `insert` call. +/// +/// If the given expression is not an `insert` call into a `BTreeMap` or a `HashMap`, return `None`. fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { if let ExprKind::MethodCall(_, map, [key, value], _) = expr.kind { let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; @@ -298,7 +335,7 @@ struct Insertion<'tcx> { value: &'tcx Expr<'tcx>, } -/// This visitor needs to do a multiple things: +/// This visitor needs to do multiple things: /// * Find all usages of the map. An insertion can only be made before any other usages of the map. /// * Determine if there's an insertion using the same key. There's no need for the entry api /// otherwise. @@ -346,7 +383,7 @@ impl<'tcx> InsertSearcher<'_, 'tcx> { res } - /// Visits an expression which is not itself in a tail position, but other sibling expressions + /// Visit an expression which is not itself in a tail position, but other sibling expressions /// may be. e.g. if conditions fn visit_non_tail_expr(&mut self, e: &'tcx Expr<'_>) { let in_tail_pos = self.in_tail_pos; @@ -354,6 +391,19 @@ impl<'tcx> InsertSearcher<'_, 'tcx> { self.visit_expr(e); self.in_tail_pos = in_tail_pos; } + + /// Visit the key and value expression of an insert expression. + /// There may not be uses of the map in either of those two either. + fn visit_insert_expr_arguments(&mut self, e: &InsertExpr<'tcx>) { + let in_tail_pos = self.in_tail_pos; + let allow_insert_closure = self.allow_insert_closure; + let is_single_insert = self.is_single_insert; + walk_expr(self, e.key); + walk_expr(self, e.value); + self.in_tail_pos = in_tail_pos; + self.allow_insert_closure = allow_insert_closure; + self.is_single_insert = is_single_insert; + } } impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) { @@ -425,6 +475,7 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { match try_parse_insert(self.cx, expr) { Some(insert_expr) if SpanlessEq::new(self.cx).eq_expr(self.map, insert_expr.map) => { + self.visit_insert_expr_arguments(&insert_expr); // Multiple inserts, inserts with a different key, and inserts from a macro can't use the entry api. if self.is_map_used || !SpanlessEq::new(self.cx).eq_expr(self.key, insert_expr.key) diff --git a/tests/ui/entry.fixed b/tests/ui/entry.fixed index 4099fe7e1393e..71ec13f461060 100644 --- a/tests/ui/entry.fixed +++ b/tests/ui/entry.fixed @@ -165,4 +165,15 @@ pub fn issue_10331() { } } +/// Issue 11935 +/// Do not suggest using entries if the map is used inside the `insert` expression. +pub fn issue_11935() { + let mut counts: HashMap = HashMap::new(); + if !counts.contains_key(&1) { + counts.insert(1, 1); + } else { + counts.insert(1, counts.get(&1).unwrap() + 1); + } +} + fn main() {} diff --git a/tests/ui/entry.rs b/tests/ui/entry.rs index 409be0aa06019..86092b7c055a7 100644 --- a/tests/ui/entry.rs +++ b/tests/ui/entry.rs @@ -169,4 +169,15 @@ pub fn issue_10331() { } } +/// Issue 11935 +/// Do not suggest using entries if the map is used inside the `insert` expression. +pub fn issue_11935() { + let mut counts: HashMap = HashMap::new(); + if !counts.contains_key(&1) { + counts.insert(1, 1); + } else { + counts.insert(1, counts.get(&1).unwrap() + 1); + } +} + fn main() {} From 9f4a58f6162c66c76ce16e2ecbe3e757d6fbb6db Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 26 Feb 2024 12:25:04 +0100 Subject: [PATCH 007/137] Add new `mixed_attributes_style` lint --- CHANGELOG.md | 1 + clippy_lints/src/attrs.rs | 55 ++++++++++++++++++++++++++++++ clippy_lints/src/declared_lints.rs | 1 + 3 files changed, 57 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0b01742deb05..20fc17df3c489 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5423,6 +5423,7 @@ Released 2018-09-13 [`missing_spin_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_spin_loop [`missing_trait_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_trait_methods [`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes +[`mixed_attributes_style`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_attributes_style [`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals [`mixed_read_write_in_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_read_write_in_expression [`mod_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#mod_module_files diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index f2937d51340b8..d3ca4d3380656 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -485,6 +485,33 @@ declare_clippy_lint! { "usage of `cfg_attr(clippy, allow(clippy::lint))` instead of `allow(clippy::lint)`" } +declare_clippy_lint! { + /// ### What it does + /// Checks that an item has only one kind of attributes. + /// + /// ### Why is this bad? + /// Having both kinds of attributes makes it more complicated to read code. + /// + /// ### 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, + suspicious, + "item has both inner and outer attributes" +} + declare_lint_pass!(Attributes => [ ALLOW_ATTRIBUTES_WITHOUT_REASON, INLINE_ALWAYS, @@ -849,11 +876,13 @@ impl_lint_pass!(EarlyAttributes => [ MAYBE_MISUSED_CFG, DEPRECATED_CLIPPY_CFG_ATTR, UNNECESSARY_CLIPPY_CFG, + MIXED_ATTRIBUTES_STYLE, ]); impl EarlyLintPass for EarlyAttributes { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) { check_empty_line_after_outer_attr(cx, item); + check_mixed_attributes(cx, item); } fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { @@ -867,6 +896,32 @@ impl EarlyLintPass for EarlyAttributes { extract_msrv_attr!(EarlyContext); } +fn check_mixed_attributes(cx: &EarlyContext<'_>, item: &rustc_ast::Item) { + let mut has_outer = false; + let mut has_inner = false; + + for attr in &item.attrs { + if attr.span.from_expansion() { + continue; + } + match attr.style { + AttrStyle::Inner => has_inner = true, + AttrStyle::Outer => has_outer = true, + } + } + if !has_outer || !has_inner { + return; + } + let mut attrs_iter = item.attrs.iter().filter(|attr| !attr.span.from_expansion()); + let span = attrs_iter.next().unwrap().span; + span_lint( + cx, + MIXED_ATTRIBUTES_STYLE, + span.with_hi(attrs_iter.last().unwrap().span.hi()), + "item has both inner and outer attributes", + ); +} + /// Check for empty lines after outer attributes. /// /// Attributes and documentation comments are both considered outer attributes diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index fb3ae2457e3c4..a453386154d97 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -58,6 +58,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::attrs::INLINE_ALWAYS_INFO, crate::attrs::MAYBE_MISUSED_CFG_INFO, crate::attrs::MISMATCHED_TARGET_OS_INFO, + crate::attrs::MIXED_ATTRIBUTES_STYLE_INFO, crate::attrs::NON_MINIMAL_CFG_INFO, crate::attrs::SHOULD_PANIC_WITHOUT_EXPECT_INFO, crate::attrs::UNNECESSARY_CLIPPY_CFG_INFO, From 28738234acfd10c12d0400dc75940f3d35821113 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 26 Feb 2024 12:25:28 +0100 Subject: [PATCH 008/137] Add ui test for `mixed_attributes_style` --- tests/ui/mixed_attributes_style.rs | 39 ++++++++++++++++++++++++++ tests/ui/mixed_attributes_style.stderr | 30 ++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 tests/ui/mixed_attributes_style.rs create mode 100644 tests/ui/mixed_attributes_style.stderr diff --git a/tests/ui/mixed_attributes_style.rs b/tests/ui/mixed_attributes_style.rs new file mode 100644 index 0000000000000..ad93e3019fa65 --- /dev/null +++ b/tests/ui/mixed_attributes_style.rs @@ -0,0 +1,39 @@ +#![warn(clippy::mixed_attributes_style)] + +#[allow(unused)] //~ ERROR: item has both inner and outer attributes +fn foo1() { + #![allow(unused)] +} + +#[allow(unused)] +#[allow(unused)] +fn foo2() {} + +fn foo3() { + #![allow(unused)] + #![allow(unused)] +} + +/// linux +//~^ ERROR: item has both inner and outer attributes +fn foo4() { + //! windows +} + +/// linux +/// windows +fn foo5() {} + +fn foo6() { + //! linux + //! windows +} + +#[allow(unused)] //~ ERROR: item has both inner and outer attributes +mod bar { + #![allow(unused)] +} + +fn main() { + // test code goes here +} diff --git a/tests/ui/mixed_attributes_style.stderr b/tests/ui/mixed_attributes_style.stderr new file mode 100644 index 0000000000000..d1d5cd3f47f31 --- /dev/null +++ b/tests/ui/mixed_attributes_style.stderr @@ -0,0 +1,30 @@ +error: item has both inner and outer attributes + --> tests/ui/mixed_attributes_style.rs:3:1 + | +LL | / #[allow(unused)] +LL | | fn foo1() { +LL | | #![allow(unused)] + | |_____________________^ + | + = note: `-D clippy::mixed-attributes-style` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mixed_attributes_style)]` + +error: item has both inner and outer attributes + --> tests/ui/mixed_attributes_style.rs:17:1 + | +LL | / /// linux +LL | | +LL | | fn foo4() { +LL | | //! windows + | |_______________^ + +error: item has both inner and outer attributes + --> tests/ui/mixed_attributes_style.rs:32:1 + | +LL | / #[allow(unused)] +LL | | mod bar { +LL | | #![allow(unused)] + | |_____________________^ + +error: aborting due to 3 previous errors + From f30138623bd9a078698328a32785780cee379e8d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 27 Feb 2024 11:18:27 +0100 Subject: [PATCH 009/137] Update ui tests --- tests/ui/empty_docs.rs | 2 ++ tests/ui/empty_docs.stderr | 18 +++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/ui/empty_docs.rs b/tests/ui/empty_docs.rs index c47a603e71b43..272fab7d5ca1a 100644 --- a/tests/ui/empty_docs.rs +++ b/tests/ui/empty_docs.rs @@ -1,5 +1,7 @@ #![allow(unused)] #![warn(clippy::empty_docs)] +#![allow(clippy::mixed_attributes_style)] + mod outer { //! diff --git a/tests/ui/empty_docs.stderr b/tests/ui/empty_docs.stderr index 3f1d071fb13ce..f12aead6aa75e 100644 --- a/tests/ui/empty_docs.stderr +++ b/tests/ui/empty_docs.stderr @@ -1,5 +1,5 @@ error: empty doc comment - --> tests/ui/empty_docs.rs:4:5 + --> tests/ui/empty_docs.rs:6:5 | LL | //! | ^^^ @@ -9,7 +9,7 @@ LL | //! = help: to override `-D warnings` add `#[allow(clippy::empty_docs)]` error: empty doc comment - --> tests/ui/empty_docs.rs:12:5 + --> tests/ui/empty_docs.rs:14:5 | LL | /// | ^^^ @@ -17,7 +17,7 @@ LL | /// = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:14:9 + --> tests/ui/empty_docs.rs:16:9 | LL | /// | ^^^ @@ -25,7 +25,7 @@ LL | /// = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:25:5 + --> tests/ui/empty_docs.rs:27:5 | LL | #[doc = ""] | ^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | #[doc = ""] = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:28:5 + --> tests/ui/empty_docs.rs:30:5 | LL | / #[doc = ""] LL | | #[doc = ""] @@ -42,7 +42,7 @@ LL | | #[doc = ""] = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:35:5 + --> tests/ui/empty_docs.rs:37:5 | LL | /// | ^^^ @@ -50,7 +50,7 @@ LL | /// = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:48:13 + --> tests/ui/empty_docs.rs:50:13 | LL | /*! */ | ^^^^^^ @@ -58,7 +58,7 @@ LL | /*! */ = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:56:13 + --> tests/ui/empty_docs.rs:58:13 | LL | /// | ^^^ @@ -66,7 +66,7 @@ LL | /// = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:64:9 + --> tests/ui/empty_docs.rs:66:9 | LL | /// | ^^^ From 7be6e2178e89dad8b619742c566fdee948414acc Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Tue, 27 Feb 2024 15:25:18 +0100 Subject: [PATCH 010/137] Merge commit '10136170fe9ed01e46aeb4f4479175b79eb0e3c7' into clippy-subtree-update --- .github/driver.sh | 4 +- CHANGELOG.md | 5 + Cargo.toml | 6 +- book/src/configuration.md | 50 +- book/src/development/emitting_lints.md | 10 +- book/src/development/writing_tests.md | 6 +- book/src/lint_configuration.md | 2 +- clippy_config/src/conf.rs | 4 +- clippy_config/src/lib.rs | 2 +- clippy_dev/Cargo.toml | 2 +- clippy_lints/Cargo.toml | 2 +- clippy_lints/src/asm_syntax.rs | 37 +- clippy_lints/src/attrs.rs | 221 +++++++- clippy_lints/src/blocks_in_conditions.rs | 17 +- clippy_lints/src/booleans.rs | 110 ++++ clippy_lints/src/box_default.rs | 71 ++- .../src/casts/cast_possible_truncation.rs | 3 +- clippy_lints/src/casts/cast_sign_loss.rs | 310 ++++++++--- clippy_lints/src/casts/ref_as_ptr.rs | 12 +- clippy_lints/src/casts/unnecessary_cast.rs | 5 +- clippy_lints/src/collection_is_never_read.rs | 8 +- clippy_lints/src/declared_lints.rs | 5 + clippy_lints/src/dereference.rs | 8 +- clippy_lints/src/disallowed_macros.rs | 84 ++- clippy_lints/src/doc/mod.rs | 61 ++- clippy_lints/src/drop_forget_ref.rs | 5 +- clippy_lints/src/format_args.rs | 511 +++++++++--------- clippy_lints/src/format_impl.rs | 203 +++---- clippy_lints/src/implied_bounds_in_impls.rs | 242 +++++---- clippy_lints/src/incompatible_msrv.rs | 18 +- clippy_lints/src/index_refutable_slice.rs | 4 +- clippy_lints/src/indexing_slicing.rs | 1 + clippy_lints/src/item_name_repetitions.rs | 1 - .../src/iter_not_returning_iterator.rs | 5 +- clippy_lints/src/lib.rs | 6 +- clippy_lints/src/loops/infinite_loop.rs | 11 +- clippy_lints/src/manual_is_ascii_check.rs | 2 +- clippy_lints/src/matches/match_same_arms.rs | 66 ++- clippy_lints/src/matches/needless_match.rs | 62 +-- clippy_lints/src/matches/redundant_guards.rs | 12 +- .../matches/significant_drop_in_scrutinee.rs | 7 +- clippy_lints/src/mem_replace.rs | 6 +- ...se_sensitive_file_extension_comparisons.rs | 1 + clippy_lints/src/methods/clone_on_copy.rs | 7 +- clippy_lints/src/methods/filter_map.rs | 2 +- clippy_lints/src/methods/mod.rs | 54 +- clippy_lints/src/methods/needless_collect.rs | 184 ++++--- .../src/methods/read_line_without_trim.rs | 95 +++- .../unnecessary_fallible_conversions.rs | 141 +++-- .../src/methods/unnecessary_get_then_check.rs | 85 +++ .../src/methods/unnecessary_to_owned.rs | 98 +++- clippy_lints/src/min_ident_chars.rs | 46 +- clippy_lints/src/multiple_bound_locations.rs | 84 +++ clippy_lints/src/needless_bool.rs | 7 +- clippy_lints/src/needless_pass_by_ref_mut.rs | 5 +- clippy_lints/src/new_without_default.rs | 4 - clippy_lints/src/no_effect.rs | 13 +- clippy_lints/src/non_canonical_impls.rs | 4 +- clippy_lints/src/non_expressive_names.rs | 146 ++--- clippy_lints/src/only_used_in_recursion.rs | 16 +- .../src/operators/double_comparison.rs | 1 - clippy_lints/src/operators/op_ref.rs | 2 +- clippy_lints/src/pub_underscore_fields.rs | 10 +- clippy_lints/src/question_mark.rs | 14 +- clippy_lints/src/redundant_closure_call.rs | 10 +- clippy_lints/src/same_name_method.rs | 36 +- clippy_lints/src/single_call_fn.rs | 130 +++-- .../src/slow_vector_initialization.rs | 2 +- clippy_lints/src/strlen_on_c_strings.rs | 8 +- clippy_lints/src/to_string_trait_impl.rs | 3 + clippy_lints/src/tuple_array_conversions.rs | 5 +- .../src/undocumented_unsafe_blocks.rs | 200 ++++--- clippy_lints/src/unit_types/let_unit_value.rs | 3 +- clippy_lints/src/unused_unit.rs | 1 + .../internal_lints/metadata_collector.rs | 2 - clippy_lints/src/vec.rs | 211 ++++---- clippy_utils/Cargo.toml | 2 +- clippy_utils/src/ast_utils.rs | 8 +- clippy_utils/src/diagnostics.rs | 10 +- clippy_utils/src/hir_utils.rs | 5 +- clippy_utils/src/lib.rs | 13 +- clippy_utils/src/paths.rs | 2 +- clippy_utils/src/qualify_min_const_fn.rs | 6 +- declare_clippy_lint/Cargo.toml | 2 +- lintcheck/src/main.rs | 6 +- rust-toolchain | 2 +- src/driver.rs | 2 + tests/compile-test.rs | 39 +- .../multiple_config_files/warn/Cargo.stderr | 2 +- .../check_clippy_version_attribute.stderr | 10 +- tests/ui-internal/check_formulation.stderr | 4 +- .../collapsible_span_lint_calls.stderr | 12 +- .../default_deprecation_reason.stderr | 4 +- tests/ui-internal/default_lint.stderr | 4 +- tests/ui-internal/disallow_span_lint.stderr | 4 +- .../interning_defined_symbol.stderr | 10 +- .../ui-internal/invalid_msrv_attr_impl.stderr | 6 +- tests/ui-internal/invalid_paths.stderr | 6 +- .../ui-internal/lint_without_lint_pass.stderr | 4 +- tests/ui-internal/outer_expn_data.stderr | 4 +- tests/ui-internal/unnecessary_def_path.stderr | 32 +- ...unnecessary_def_path_hardcoded_path.stderr | 6 +- .../ui-internal/unnecessary_symbol_str.stderr | 12 +- .../absolute_paths.allow_crates.stderr | 8 +- .../absolute_paths.disallow_crates.stderr | 22 +- .../uninlined_format_args.stderr | 12 +- .../arithmetic_side_effects_allowed.stderr | 18 +- .../array_size_threshold.stderr | 6 +- .../await_holding_invalid_type.stderr | 6 +- tests/ui-toml/bad_toml/conf_bad_toml.stderr | 2 +- .../bad_toml_type/conf_bad_type.stderr | 2 +- .../conf_deprecated_key.stderr | 6 +- tests/ui-toml/dbg_macro/dbg_macro.stderr | 18 +- .../decimal_literal_representation.stderr | 2 +- .../auxiliary/proc_macros.rs | 29 + tests/ui-toml/disallowed_macros/clippy.toml | 1 + .../disallowed_macros/disallowed_macros.rs | 6 + .../disallowed_macros.stderr | 38 +- .../disallowed_names.stderr | 4 +- .../disallowed_names.stderr | 2 +- .../disallowed_script_idents.stderr | 2 +- .../doc_markdown.stderr | 2 +- .../doc_markdown.stderr | 6 +- .../duplicated_keys/duplicated_keys.stderr | 2 +- .../duplicated_keys.stderr | 4 +- .../duplicated_keys.stderr | 4 +- .../enum_variant_size.stderr | 2 +- .../excessive_nesting.stderr | 74 +-- tests/ui-toml/expect_used/expect_used.stderr | 4 +- .../explicit_iter_loop.stderr | 4 +- .../fn_params_excessive_bools/test.stderr | 2 +- tests/ui-toml/functions_maxlines/test.stderr | 8 +- .../ifs_same_cond/ifs_same_cond.stderr | 4 +- .../impl_trait_in_params.stderr | 2 +- .../invalid_min_rust_version.stderr | 2 +- .../threshold5/item_name_repetitions.stderr | 4 +- .../large_futures/large_futures.stderr | 2 +- .../large_include_file.stderr | 4 +- .../large_stack_frames.stderr | 2 +- .../large_types_passed_by_value.stderr | 2 +- .../lint_decimal_readability/test.stderr | 4 +- .../manual_let_else/manual_let_else.stderr | 2 +- .../index_refutable_slice.stderr | 4 +- .../min_ident_chars/auxiliary/extern_types.rs | 6 + .../min_ident_chars/min_ident_chars.rs | 5 +- .../min_ident_chars/min_ident_chars.stderr | 28 +- .../min_rust_version/min_rust_version.stderr | 2 +- ...conf_missing_enforced_import_rename.stderr | 12 +- .../module_inception/module_inception.stderr | 4 +- .../modulo_arithmetic.stderr | 8 +- .../conf_nonstandard_macro_braces.stderr | 16 +- tests/ui-toml/print_macro/print_macro.stderr | 4 +- .../private-doc-errors/doc_lints.stderr | 20 +- .../pub_crate_missing_doc.stderr | 14 +- ...ub_underscore_fields.all_pub_fields.stderr | 14 +- .../pub_underscore_fields.exported.stderr | 2 +- .../pub_underscore_fields.rs | 6 + .../result_large_err/result_large_err.stderr | 2 +- tests/ui-toml/semicolon_block/both.stderr | 8 +- .../semicolon_inside_block.stderr | 2 +- .../semicolon_outside_block.stderr | 6 +- .../test.stderr | 28 +- .../struct_excessive_bools/test.stderr | 2 +- .../suppress_lint_in_const/test.stderr | 12 +- .../conf_french_disallowed_name.stderr | 14 +- .../conf_disallowed_methods.stderr | 28 +- .../conf_disallowed_types.stderr | 42 +- tests/ui-toml/toml_trivially_copy/test.stderr | 4 +- .../toml_unknown_key/conf_unknown_key.stderr | 6 +- .../too_large_for_stack/boxed_local.stderr | 2 +- .../too_large_for_stack/useless_vec.stderr | 2 +- .../too_many_arguments.stderr | 2 +- .../type_complexity/type_complexity.stderr | 2 +- .../type_repetition_in_bounds/main.stderr | 2 +- .../undocumented_unsafe_blocks.default.stderr | 74 +-- ...undocumented_unsafe_blocks.disabled.stderr | 94 ++-- .../unnecessary_box_returns.stderr | 2 +- tests/ui-toml/unwrap_used/unwrap_used.stderr | 56 +- .../upper_case_acronyms.stderr | 26 +- tests/ui-toml/vec_box_sized/test.stderr | 6 +- .../verbose_bit_mask/verbose_bit_mask.stderr | 2 +- .../wildcard_imports/wildcard_imports.stderr | 6 +- .../wildcard_imports.stderr | 2 +- tests/ui/absurd-extreme-comparisons.stderr | 36 +- tests/ui/allow_attributes.stderr | 4 +- .../ui/allow_attributes_without_reason.stderr | 10 +- tests/ui/almost_complete_range.stderr | 54 +- tests/ui/approx_const.rs | 1 - tests/ui/approx_const.stderr | 46 +- tests/ui/arc_with_non_send_sync.stderr | 6 +- tests/ui/arithmetic_side_effects.stderr | 238 ++++---- tests/ui/as_conversions.stderr | 6 +- tests/ui/as_ptr_cast_mut.stderr | 4 +- tests/ui/as_underscore.stderr | 4 +- tests/ui/asm_syntax_not_x86.rs | 24 + ...ntax.stderr => asm_syntax_x86.i686.stderr} | 36 +- tests/ui/{asm_syntax.rs => asm_syntax_x86.rs} | 23 +- tests/ui/asm_syntax_x86.x86_64.stderr | 70 +++ tests/ui/assertions_on_constants.stderr | 20 +- tests/ui/assertions_on_result_states.stderr | 14 +- tests/ui/assign_ops.stderr | 22 +- tests/ui/assign_ops2.stderr | 20 +- tests/ui/async_yields_async.stderr | 12 +- tests/ui/attrs.stderr | 6 +- tests/ui/auxiliary/proc_macro_attr.rs | 20 + tests/ui/await_holding_lock.stderr | 52 +- tests/ui/await_holding_refcell_ref.stderr | 24 +- tests/ui/bind_instead_of_map.stderr | 8 +- tests/ui/bind_instead_of_map_multipart.stderr | 12 +- tests/ui/bit_masks.stderr | 34 +- .../blanket_clippy_restriction_lints.stderr | 6 +- tests/ui/blocks_in_conditions.fixed | 13 + tests/ui/blocks_in_conditions.rs | 13 + tests/ui/blocks_in_conditions.stderr | 8 +- tests/ui/blocks_in_conditions_closure.stderr | 6 +- tests/ui/bool_assert_comparison.stderr | 66 +-- tests/ui/bool_comparison.fixed | 2 +- tests/ui/bool_comparison.rs | 2 +- tests/ui/bool_comparison.stderr | 50 +- tests/ui/bool_to_int_with_if.stderr | 18 +- tests/ui/borrow_as_ptr.stderr | 4 +- tests/ui/borrow_as_ptr_no_std.stderr | 4 +- tests/ui/borrow_box.stderr | 22 +- tests/ui/borrow_deref_ref.stderr | 6 +- tests/ui/borrow_deref_ref_unfixable.stderr | 2 +- .../enums.stderr | 20 +- .../others.stderr | 30 +- .../traits.stderr | 32 +- tests/ui/box_collection.stderr | 18 +- tests/ui/box_default.fixed | 18 +- tests/ui/box_default.rs | 16 + tests/ui/box_default.stderr | 48 +- tests/ui/boxed_local.stderr | 8 +- .../shared_at_bottom.stderr | 20 +- .../shared_at_top.stderr | 20 +- .../shared_at_top_and_bottom.stderr | 22 +- .../valid_if_blocks.stderr | 22 +- tests/ui/builtin_type_shadow.stderr | 4 +- tests/ui/bytecount.stderr | 8 +- tests/ui/bytes_count_to_len.stderr | 8 +- tests/ui/bytes_nth.stderr | 6 +- ...sensitive_file_extension_comparisons.fixed | 5 + ...se_sensitive_file_extension_comparisons.rs | 5 + ...ensitive_file_extension_comparisons.stderr | 12 +- tests/ui/cast.rs | 67 ++- tests/ui/cast.stderr | 270 ++++++--- tests/ui/cast_abs_to_unsigned.stderr | 36 +- tests/ui/cast_alignment.stderr | 8 +- tests/ui/cast_enum_constructor.stderr | 4 +- tests/ui/cast_lossless_bool.stderr | 28 +- tests/ui/cast_lossless_float.stderr | 22 +- tests/ui/cast_lossless_integer.stderr | 42 +- tests/ui/cast_nan_to_int.stderr | 12 +- tests/ui/cast_raw_slice_pointer_cast.stderr | 14 +- tests/ui/cast_size.32bit.stderr | 38 +- tests/ui/cast_size.64bit.stderr | 36 +- tests/ui/cast_slice_different_sizes.stderr | 28 +- tests/ui/cfg_attr_cargo_clippy.fixed | 13 + tests/ui/cfg_attr_cargo_clippy.rs | 13 + tests/ui/cfg_attr_cargo_clippy.stderr | 47 ++ tests/ui/cfg_attr_rustfmt.stderr | 6 +- tests/ui/cfg_features.stderr | 16 +- tests/ui/char_lit_as_u8.stderr | 2 +- tests/ui/char_lit_as_u8_suggestions.stderr | 8 +- tests/ui/checked_conversions.stderr | 34 +- .../complex_conditionals.stderr | 44 +- .../complex_conditionals_nested.stderr | 8 +- .../checked_unwrap/simple_conditionals.stderr | 54 +- tests/ui/clear_with_drain.stderr | 42 +- tests/ui/clone_on_copy.stderr | 18 +- tests/ui/cloned_instead_of_copied.stderr | 16 +- tests/ui/cmp_null.stderr | 4 +- .../ui/cmp_owned/asymmetric_partial_eq.stderr | 12 +- tests/ui/cmp_owned/comparison_flip.stderr | 4 +- tests/ui/cmp_owned/with_suggestion.fixed | 2 +- tests/ui/cmp_owned/with_suggestion.stderr | 12 +- tests/ui/cmp_owned/without_suggestion.stderr | 6 +- tests/ui/cognitive_complexity.stderr | 40 +- .../ui/cognitive_complexity_attr_used.stderr | 2 +- tests/ui/collapsible_else_if.stderr | 16 +- tests/ui/collapsible_if.stderr | 18 +- tests/ui/collapsible_match.stderr | 48 +- tests/ui/collapsible_match2.stderr | 20 +- tests/ui/collapsible_str_replace.stderr | 28 +- tests/ui/collection_is_never_read.stderr | 40 +- tests/ui/comparison_chain.stderr | 14 +- tests/ui/comparison_to_empty.stderr | 18 +- tests/ui/const_comparisons.stderr | 62 +-- tests/ui/copy_iterator.stderr | 2 +- tests/ui/crashes/ice-10148.stderr | 2 +- tests/ui/crashes/ice-10645.stderr | 4 +- tests/ui/crashes/ice-10912.stderr | 4 +- tests/ui/crashes/ice-11065.rs | 1 - tests/ui/crashes/ice-11422.stderr | 2 +- tests/ui/crashes/ice-11803.stderr | 4 +- tests/ui/crashes/ice-12253.rs | 5 + tests/ui/crashes/ice-2774.stderr | 2 +- tests/ui/crashes/ice-360.stderr | 6 +- tests/ui/crashes/ice-3717.stderr | 4 +- tests/ui/crashes/ice-3891.stderr | 2 +- tests/ui/crashes/ice-3969.stderr | 10 +- tests/ui/crashes/ice-5497.stderr | 2 +- tests/ui/crashes/ice-5835.stderr | 2 +- tests/ui/crashes/ice-5872.stderr | 2 +- tests/ui/crashes/ice-6250.stderr | 4 +- tests/ui/crashes/ice-6251.stderr | 8 +- tests/ui/crashes/ice-6252.stderr | 6 +- tests/ui/crashes/ice-6255.rs | 2 +- tests/ui/crashes/ice-6255.stderr | 2 +- tests/ui/crashes/ice-6256.stderr | 2 +- tests/ui/crashes/ice-7169.stderr | 2 +- tests/ui/crashes/ice-7868.stderr | 2 +- tests/ui/crashes/ice-7869.stderr | 2 +- tests/ui/crashes/ice-8250.stderr | 2 +- tests/ui/crashes/ice-8850.stderr | 6 +- tests/ui/crashes/ice-9041.stderr | 2 +- tests/ui/crashes/ice-9405.stderr | 2 +- tests/ui/crashes/ice-9445.stderr | 2 +- tests/ui/crashes/ice-9463.stderr | 8 +- tests/ui/crashes/ice-96721.stderr | 2 +- .../needless_lifetimes_impl_trait.stderr | 4 +- ...needless_pass_by_value-w-late-bound.stderr | 4 +- tests/ui/crate_in_macro_def.stderr | 2 +- .../ui/crate_level_checks/no_std_swap.stderr | 2 +- .../std_main_recursion.stderr | 2 +- tests/ui/create_dir.stderr | 4 +- tests/ui/dbg_macro/dbg_macro.stderr | 38 +- tests/ui/debug_assert_with_mut_call.stderr | 56 +- .../ui/decimal_literal_representation.stderr | 14 +- .../enums.stderr | 24 +- .../declare_interior_mutable_const/others.rs | 5 +- .../others.stderr | 10 +- .../declare_interior_mutable_const/traits.rs | 3 +- .../traits.stderr | 22 +- tests/ui/def_id_nocore.stderr | 2 +- .../default_constructed_unit_structs.stderr | 12 +- tests/ui/default_instead_of_iter_empty.stderr | 6 +- ...efault_instead_of_iter_empty_no_std.stderr | 4 +- tests/ui/default_numeric_fallback_f64.stderr | 46 +- tests/ui/default_numeric_fallback_i32.stderr | 56 +- tests/ui/default_trait_access.stderr | 18 +- tests/ui/default_union_representation.stderr | 8 +- tests/ui/deprecated.stderr | 32 +- tests/ui/deprecated_old.stderr | 6 +- tests/ui/deref_addrof.stderr | 20 +- tests/ui/deref_addrof_double_trigger.stderr | 6 +- tests/ui/deref_by_slicing.stderr | 18 +- tests/ui/derivable_impls.stderr | 16 +- tests/ui/derive.stderr | 20 +- tests/ui/derive_ord_xor_partial_ord.stderr | 16 +- tests/ui/derive_partial_eq_without_eq.stderr | 22 +- tests/ui/derived_hash_with_manual_eq.stderr | 8 +- tests/ui/disallowed_names.stderr | 28 +- tests/ui/disallowed_script_idents.stderr | 6 +- tests/ui/diverging_sub_expression.stderr | 22 +- tests/ui/doc/doc-fixable.stderr | 62 +-- tests/ui/doc/unbalanced_ticks.stderr | 16 +- tests/ui/doc_errors.stderr | 14 +- tests/ui/doc_link_with_quotes.stderr | 4 +- tests/ui/doc_unsafe.stderr | 12 +- tests/ui/double_comparison.stderr | 16 +- tests/ui/double_must_use.stderr | 8 +- tests/ui/double_neg.stderr | 2 +- tests/ui/double_parens.stderr | 12 +- tests/ui/drain_collect.stderr | 22 +- tests/ui/drop_non_drop.stderr | 8 +- tests/ui/duplicate_underscore_argument.stderr | 2 +- tests/ui/duration_subsec.stderr | 10 +- tests/ui/eager_transmute.stderr | 34 +- tests/ui/else_if_without_else.stderr | 4 +- tests/ui/empty_docs.rs | 67 +++ tests/ui/empty_docs.stderr | 77 +++ tests/ui/empty_drop.stderr | 4 +- tests/ui/empty_enum.stderr | 2 +- .../empty_enum_variants_with_brackets.stderr | 8 +- tests/ui/empty_line_after_doc_comments.stderr | 6 +- .../empty_line_after_outer_attribute.stderr | 12 +- tests/ui/empty_loop.stderr | 6 +- tests/ui/empty_loop_no_std.stderr | 4 +- tests/ui/empty_structs_with_brackets.stderr | 4 +- tests/ui/endian_bytes.stderr | 172 +++--- tests/ui/entry.stderr | 20 +- tests/ui/entry_btree.stderr | 2 +- tests/ui/entry_with_else.stderr | 14 +- tests/ui/enum_clike_unportable_variant.stderr | 18 +- tests/ui/enum_glob_use.stderr | 6 +- tests/ui/enum_variants.stderr | 32 +- tests/ui/eprint_with_newline.stderr | 18 +- tests/ui/eq_op.stderr | 58 +- tests/ui/eq_op_macros.stderr | 24 +- tests/ui/equatable_if_let.stderr | 28 +- tests/ui/erasing_op.stderr | 10 +- tests/ui/err_expect.stderr | 4 +- tests/ui/error_impl_error.stderr | 14 +- tests/ui/eta.stderr | 62 +-- tests/ui/excessive_precision.stderr | 30 +- tests/ui/exhaustive_items.stderr | 10 +- tests/ui/exit1.stderr | 2 +- tests/ui/exit2.stderr | 2 +- tests/ui/expect.stderr | 6 +- tests/ui/expect_fun_call.stderr | 30 +- tests/ui/expect_tool_lint_rfc_2383.stderr | 12 +- tests/ui/explicit_auto_deref.stderr | 90 +-- tests/ui/explicit_counter_loop.stderr | 18 +- tests/ui/explicit_deref_methods.stderr | 24 +- tests/ui/explicit_into_iter_loop.stderr | 12 +- tests/ui/explicit_iter_loop.stderr | 38 +- tests/ui/explicit_write.stderr | 26 +- tests/ui/extend_with_drain.stderr | 8 +- tests/ui/extra_unused_lifetimes.stderr | 12 +- tests/ui/extra_unused_type_parameters.stderr | 16 +- ...ra_unused_type_parameters_unfixable.stderr | 6 +- tests/ui/fallible_impl_from.stderr | 18 +- tests/ui/field_reassign_with_default.stderr | 44 +- tests/ui/filetype_is_file.stderr | 6 +- tests/ui/filter_map_bool_then.stderr | 20 +- tests/ui/filter_map_identity.stderr | 8 +- tests/ui/filter_map_next.stderr | 2 +- tests/ui/filter_map_next_fixable.stderr | 4 +- tests/ui/flat_map_identity.stderr | 6 +- tests/ui/flat_map_option.stderr | 4 +- tests/ui/float_arithmetic.stderr | 34 +- tests/ui/float_cmp.stderr | 12 +- tests/ui/float_cmp_const.stderr | 16 +- tests/ui/float_equality_without_abs.stderr | 22 +- tests/ui/floating_point_abs.stderr | 16 +- tests/ui/floating_point_exp.stderr | 10 +- tests/ui/floating_point_hypot.stderr | 6 +- tests/ui/floating_point_log.stderr | 58 +- tests/ui/floating_point_logbase.stderr | 10 +- tests/ui/floating_point_mul_add.stderr | 26 +- tests/ui/floating_point_powf.stderr | 62 +-- tests/ui/floating_point_powi.stderr | 28 +- tests/ui/floating_point_rad.stderr | 16 +- tests/ui/fn_address_comparisons.stderr | 4 +- tests/ui/fn_params_excessive_bools.stderr | 14 +- tests/ui/fn_to_numeric_cast.32bit.stderr | 46 +- tests/ui/fn_to_numeric_cast.64bit.stderr | 46 +- tests/ui/fn_to_numeric_cast_any.stderr | 34 +- tests/ui/for_kv_map.stderr | 10 +- tests/ui/forget_non_drop.stderr | 8 +- tests/ui/format.stderr | 30 +- tests/ui/format_args.stderr | 50 +- tests/ui/format_args_unfixable.stderr | 36 +- tests/ui/format_collect.stderr | 18 +- tests/ui/format_push_string.stderr | 10 +- tests/ui/formatting.stderr | 12 +- tests/ui/four_forward_slashes.stderr | 10 +- .../ui/four_forward_slashes_first_line.stderr | 2 +- tests/ui/from_iter_instead_of_collect.stderr | 30 +- tests/ui/from_over_into.stderr | 14 +- tests/ui/from_over_into_unfixable.stderr | 8 +- tests/ui/from_raw_with_void_ptr.stderr | 20 +- tests/ui/from_str_radix_10.stderr | 16 +- tests/ui/functions.stderr | 32 +- tests/ui/functions_maxlines.stderr | 2 +- tests/ui/future_not_send.stderr | 36 +- tests/ui/get_first.stderr | 10 +- tests/ui/get_last_with_len.stderr | 12 +- tests/ui/get_unwrap.stderr | 62 +-- tests/ui/identity_op.stderr | 104 ++-- tests/ui/if_let_mutex.stderr | 6 +- tests/ui/if_not_else.stderr | 4 +- tests/ui/if_same_then_else.stderr | 24 +- tests/ui/if_same_then_else2.stderr | 24 +- tests/ui/if_then_some_else_none.stderr | 10 +- tests/ui/ifs_same_cond.stderr | 16 +- tests/ui/ignored_unit_patterns.stderr | 18 +- tests/ui/impl.stderr | 16 +- ...impl_hash_with_borrow_str_and_bytes.stderr | 6 +- tests/ui/impl_trait_in_params.stderr | 8 +- tests/ui/implicit_clone.stderr | 22 +- tests/ui/implicit_hasher.stderr | 12 +- tests/ui/implicit_return.stderr | 32 +- tests/ui/implicit_saturating_add.stderr | 48 +- tests/ui/implicit_saturating_sub.stderr | 46 +- tests/ui/implied_bounds_in_impls.fixed | 52 ++ tests/ui/implied_bounds_in_impls.rs | 52 ++ tests/ui/implied_bounds_in_impls.stderr | 118 +++- tests/ui/incompatible_msrv.rs | 13 + tests/ui/incompatible_msrv.stderr | 6 +- tests/ui/inconsistent_digit_grouping.stderr | 22 +- .../ui/inconsistent_struct_constructor.stderr | 4 +- .../if_let_slice_binding.stderr | 22 +- .../slice_indexing_in_macro.stderr | 4 +- tests/ui/indexing_slicing_index.stderr | 32 +- tests/ui/indexing_slicing_slice.stderr | 32 +- tests/ui/ineffective_open_options.stderr | 4 +- tests/ui/inefficient_to_string.stderr | 14 +- .../ui/infallible_destructuring_match.stderr | 8 +- tests/ui/infinite_iter.stderr | 32 +- tests/ui/infinite_loop.stderr | 22 +- tests/ui/infinite_loops.rs | 27 + tests/ui/infinite_loops.stderr | 34 +- tests/ui/inherent_to_string.stderr | 4 +- tests/ui/inline_fn_without_body.stderr | 6 +- tests/ui/inspect_for_each.stderr | 2 +- tests/ui/int_plus_one.stderr | 8 +- tests/ui/integer_division.stderr | 6 +- tests/ui/into_iter_on_ref.stderr | 54 +- tests/ui/into_iter_without_iter.stderr | 12 +- tests/ui/invalid_null_ptr_usage.stderr | 50 +- tests/ui/invalid_upcast_comparisons.stderr | 54 +- tests/ui/is_digit_ascii_radix.stderr | 6 +- tests/ui/issue-3145.stderr | 2 +- tests/ui/issue-7447.stderr | 4 +- tests/ui/issue_2356.stderr | 4 +- tests/ui/issue_4266.stderr | 6 +- tests/ui/items_after_statement.stderr | 6 +- .../in_submodule.stderr | 2 +- .../root_module.stderr | 2 +- tests/ui/iter_cloned_collect.stderr | 10 +- tests/ui/iter_count.stderr | 50 +- tests/ui/iter_filter_is_ok.stderr | 24 +- tests/ui/iter_filter_is_some.fixed | 3 +- tests/ui/iter_filter_is_some.rs | 3 +- tests/ui/iter_filter_is_some.stderr | 20 +- tests/ui/iter_kv_map.stderr | 76 +-- tests/ui/iter_next_loop.stderr | 2 +- tests/ui/iter_next_slice.stderr | 8 +- tests/ui/iter_not_returning_iterator.stderr | 6 +- tests/ui/iter_nth.stderr | 14 +- tests/ui/iter_nth_zero.stderr | 6 +- tests/ui/iter_on_empty_collections.stderr | 12 +- tests/ui/iter_on_single_items.stderr | 12 +- tests/ui/iter_out_of_bounds.stderr | 30 +- tests/ui/iter_over_hash_type.stderr | 26 +- tests/ui/iter_overeager_cloned.stderr | 38 +- tests/ui/iter_skip_next.stderr | 14 +- tests/ui/iter_skip_next_unfixable.stderr | 12 +- tests/ui/iter_skip_zero.stderr | 10 +- tests/ui/iter_with_drain.stderr | 12 +- tests/ui/iter_without_into_iter.stderr | 16 +- tests/ui/iterator_step_by_zero.stderr | 14 +- tests/ui/join_absolute_paths.stderr | 8 +- tests/ui/large_const_arrays.stderr | 18 +- tests/ui/large_digit_groups.stderr | 10 +- tests/ui/large_enum_variant.32bit.stderr | 44 +- tests/ui/large_enum_variant.64bit.stderr | 44 +- tests/ui/large_futures.stderr | 16 +- tests/ui/large_stack_arrays.stderr | 14 +- tests/ui/large_stack_frames.stderr | 6 +- tests/ui/large_types_passed_by_value.stderr | 16 +- tests/ui/len_without_is_empty.stderr | 42 +- tests/ui/len_zero.stderr | 46 +- tests/ui/len_zero_ranges.stderr | 4 +- tests/ui/let_and_return.stderr | 10 +- tests/ui/let_if_seq.stderr | 8 +- tests/ui/let_underscore_future.stderr | 6 +- tests/ui/let_underscore_lock.stderr | 8 +- tests/ui/let_underscore_must_use.stderr | 24 +- tests/ui/let_underscore_untyped.stderr | 20 +- tests/ui/let_unit.stderr | 6 +- tests/ui/let_with_type_underscore.stderr | 20 +- tests/ui/lines_filter_map_ok.stderr | 24 +- tests/ui/linkedlist.stderr | 18 +- tests/ui/literals.stderr | 40 +- tests/ui/lossy_float_literal.stderr | 22 +- tests/ui/macro_use_imports.stderr | 8 +- tests/ui/manual_assert.edition2018.stderr | 18 +- tests/ui/manual_assert.edition2021.stderr | 18 +- tests/ui/manual_async_fn.stderr | 26 +- tests/ui/manual_bits.stderr | 58 +- tests/ui/manual_c_str_literals.stderr | 26 +- tests/ui/manual_clamp.stderr | 70 +-- tests/ui/manual_filter.stderr | 30 +- tests/ui/manual_filter_map.stderr | 76 +-- tests/ui/manual_find.stderr | 4 +- tests/ui/manual_find_fixable.stderr | 24 +- tests/ui/manual_find_map.stderr | 78 +-- tests/ui/manual_flatten.stderr | 36 +- tests/ui/manual_float_methods.stderr | 12 +- tests/ui/manual_hash_one.stderr | 8 +- tests/ui/manual_instant_elapsed.stderr | 4 +- tests/ui/manual_is_ascii_check.stderr | 44 +- tests/ui/manual_is_variant_and.stderr | 16 +- tests/ui/manual_let_else.stderr | 60 +- tests/ui/manual_let_else_match.stderr | 20 +- tests/ui/manual_let_else_question_mark.stderr | 14 +- tests/ui/manual_main_separator_str.stderr | 8 +- tests/ui/manual_map_option.stderr | 42 +- tests/ui/manual_map_option_2.stderr | 10 +- .../manual_memcpy/with_loop_counters.stderr | 22 +- .../without_loop_counters.stderr | 32 +- tests/ui/manual_next_back.stderr | 4 +- tests/ui/manual_non_exhaustive_enum.stderr | 8 +- tests/ui/manual_non_exhaustive_struct.stderr | 20 +- tests/ui/manual_ok_or.stderr | 10 +- tests/ui/manual_range_patterns.stderr | 38 +- tests/ui/manual_rem_euclid.stderr | 20 +- tests/ui/manual_retain.stderr | 76 +-- tests/ui/manual_saturating_arithmetic.stderr | 48 +- tests/ui/manual_slice_size_calculation.stderr | 14 +- tests/ui/manual_split_once.stderr | 38 +- tests/ui/manual_str_repeat.stderr | 20 +- tests/ui/manual_string_new.stderr | 18 +- tests/ui/manual_strip.stderr | 32 +- tests/ui/manual_try_fold.stderr | 8 +- tests/ui/manual_unwrap_or.stderr | 28 +- tests/ui/manual_while_let_some.stderr | 14 +- tests/ui/many_single_char_names.stderr | 10 +- tests/ui/map_clone.stderr | 30 +- tests/ui/map_collect_result_unit.stderr | 4 +- tests/ui/map_err.stderr | 2 +- tests/ui/map_flatten.stderr | 8 +- tests/ui/map_flatten_fixable.stderr | 18 +- tests/ui/map_identity.stderr | 22 +- tests/ui/map_unwrap_or.stderr | 30 +- tests/ui/map_unwrap_or_fixable.stderr | 4 +- tests/ui/match_as_ref.stderr | 6 +- tests/ui/match_bool.stderr | 18 +- tests/ui/match_expr_like_matches_macro.stderr | 28 +- tests/ui/match_on_vec_items.stderr | 16 +- tests/ui/match_overlapping_arm.stderr | 32 +- tests/ui/match_ref_pats.stderr | 10 +- tests/ui/match_result_ok.stderr | 6 +- tests/ui/match_same_arms.stderr | 32 +- tests/ui/match_same_arms2.rs | 14 + tests/ui/match_same_arms2.stderr | 67 ++- .../ui/match_same_arms_non_exhaustive.stderr | 8 +- tests/ui/match_single_binding.stderr | 48 +- tests/ui/match_single_binding2.stderr | 8 +- tests/ui/match_str_case_mismatch.stderr | 14 +- tests/ui/match_wild_err_arm.stderr | 8 +- .../match_wildcard_for_single_variants.stderr | 20 +- tests/ui/mem_forget.stderr | 8 +- tests/ui/mem_replace.fixed | 8 + tests/ui/mem_replace.rs | 8 + tests/ui/mem_replace.stderr | 48 +- tests/ui/mem_replace_macro.rs | 4 +- tests/ui/mem_replace_macro.stderr | 6 +- tests/ui/mem_replace_no_std.stderr | 14 +- tests/ui/methods.stderr | 4 +- tests/ui/methods_fixable.stderr | 2 +- tests/ui/methods_unfixable.stderr | 4 +- tests/ui/min_ident_chars.rs | 6 + tests/ui/min_ident_chars.stderr | 78 ++- tests/ui/min_max.stderr | 26 +- tests/ui/min_rust_version_attr.stderr | 12 +- tests/ui/min_rust_version_invalid_attr.stderr | 12 +- tests/ui/mismatched_target_os_non_unix.stderr | 8 +- tests/ui/mismatched_target_os_unix.stderr | 34 +- tests/ui/mismatching_type_param_order.stderr | 20 +- tests/ui/misnamed_getters.stderr | 36 +- tests/ui/missing_assert_message.stderr | 32 +- tests/ui/missing_asserts_for_indexing.stderr | 94 ++-- ...sing_asserts_for_indexing_unfixable.stderr | 56 +- .../could_be_const.stderr | 22 +- tests/ui/missing_doc.stderr | 26 +- tests/ui/missing_doc_crate_missing.stderr | 2 +- tests/ui/missing_doc_impl.stderr | 14 +- tests/ui/missing_fields_in_debug.stderr | 16 +- tests/ui/missing_inline.stderr | 12 +- tests/ui/missing_panics_doc.stderr | 48 +- tests/ui/missing_spin_loop.stderr | 12 +- tests/ui/missing_spin_loop_no_std.stderr | 2 +- tests/ui/missing_trait_methods.stderr | 8 +- tests/ui/mistyped_literal_suffix.stderr | 32 +- .../ui/mixed_read_write_in_expression.stderr | 16 +- tests/ui/module_inception.stderr | 8 +- tests/ui/module_name_repetitions.stderr | 10 +- tests/ui/modulo_arithmetic_float.stderr | 20 +- tests/ui/modulo_arithmetic_integral.stderr | 34 +- .../modulo_arithmetic_integral_const.stderr | 34 +- tests/ui/modulo_one.stderr | 16 +- tests/ui/multi_assignments.stderr | 12 +- tests/ui/multiple_bound_locations.rs | 60 ++ tests/ui/multiple_bound_locations.stderr | 59 ++ tests/ui/multiple_unsafe_ops_per_block.stderr | 58 +- tests/ui/must_use_candidates.stderr | 10 +- tests/ui/must_use_unit.stderr | 6 +- tests/ui/mut_from_ref.stderr | 24 +- tests/ui/mut_key.stderr | 34 +- tests/ui/mut_mut.stderr | 18 +- tests/ui/mut_mutex_lock.stderr | 2 +- tests/ui/mut_range_bound.stderr | 14 +- tests/ui/mut_reference.stderr | 6 +- tests/ui/mutex_atomic.stderr | 22 +- tests/ui/needless_arbitrary_self_type.stderr | 12 +- ...dless_arbitrary_self_type_unfixable.stderr | 2 +- tests/ui/needless_bitwise_bool.stderr | 2 +- tests/ui/needless_bool/fixable.stderr | 42 +- tests/ui/needless_bool/simple.stderr | 8 +- tests/ui/needless_bool_assign.stderr | 10 +- tests/ui/needless_borrow.stderr | 54 +- tests/ui/needless_borrow_pat.stderr | 24 +- tests/ui/needless_borrowed_ref.stderr | 34 +- .../needless_borrows_for_generic_args.stderr | 24 +- tests/ui/needless_collect.stderr | 38 +- tests/ui/needless_collect_indirect.stderr | 32 +- tests/ui/needless_continue.stderr | 16 +- tests/ui/needless_doc_main.stderr | 8 +- tests/ui/needless_else.stderr | 2 +- tests/ui/needless_for_each_fixable.stderr | 16 +- tests/ui/needless_for_each_unfixable.stderr | 2 +- tests/ui/needless_if.stderr | 14 +- tests/ui/needless_late_init.stderr | 32 +- tests/ui/needless_lifetimes.stderr | 92 ++-- tests/ui/needless_match.stderr | 26 +- tests/ui/needless_option_as_deref.stderr | 6 +- tests/ui/needless_option_take.stderr | 2 +- .../needless_parens_on_range_literals.stderr | 12 +- tests/ui/needless_pass_by_ref_mut.stderr | 62 +-- tests/ui/needless_pass_by_value.stderr | 52 +- tests/ui/needless_pub_self.stderr | 6 +- tests/ui/needless_question_mark.stderr | 30 +- tests/ui/needless_range_loop.stderr | 28 +- tests/ui/needless_range_loop2.stderr | 16 +- tests/ui/needless_raw_string.stderr | 14 +- tests/ui/needless_raw_string_hashes.stderr | 30 +- tests/ui/needless_return.stderr | 104 ++-- .../needless_return_with_question_mark.stderr | 4 +- tests/ui/needless_splitn.stderr | 26 +- tests/ui/needless_update.stderr | 2 +- tests/ui/neg_cmp_op_on_partial_ord.stderr | 8 +- tests/ui/neg_multiply.stderr | 16 +- tests/ui/never_loop.stderr | 32 +- tests/ui/new_ret_no_self.stderr | 24 +- tests/ui/new_ret_no_self_overflow.stderr | 2 +- tests/ui/new_without_default.fixed | 10 +- tests/ui/new_without_default.rs | 4 +- tests/ui/new_without_default.stderr | 35 +- tests/ui/no_effect.stderr | 58 +- tests/ui/no_effect_async_fn.rs | 50 ++ tests/ui/no_effect_async_fn.stderr | 29 + tests/ui/no_effect_replace.stderr | 16 +- tests/ui/no_effect_return.stderr | 18 +- tests/ui/no_mangle_with_rust_abi.stderr | 10 +- tests/ui/non_canonical_clone_impl.stderr | 8 +- .../ui/non_canonical_partial_ord_impl.stderr | 4 +- ...nonical_partial_ord_impl_fully_qual.stderr | 4 +- tests/ui/non_expressive_names.stderr | 12 +- tests/ui/non_minimal_cfg.stderr | 8 +- tests/ui/non_minimal_cfg2.stderr | 2 +- tests/ui/non_octal_unix_permissions.stderr | 8 +- tests/ui/non_send_fields_in_send_ty.stderr | 52 +- tests/ui/nonminimal_bool.rs | 17 + tests/ui/nonminimal_bool.stderr | 127 ++++- tests/ui/nonminimal_bool_methods.stderr | 26 +- tests/ui/numbered_fields.stderr | 4 +- tests/ui/obfuscated_if_else.stderr | 2 +- tests/ui/octal_escapes.stderr | 18 +- tests/ui/ok_expect.stderr | 10 +- tests/ui/only_used_in_recursion.stderr | 64 +-- tests/ui/only_used_in_recursion2.stderr | 20 +- tests/ui/op_ref.stderr | 8 +- tests/ui/open_options.stderr | 16 +- tests/ui/open_options_fixable.stderr | 2 +- tests/ui/option_as_ref_cloned.stderr | 6 +- tests/ui/option_as_ref_deref.stderr | 36 +- tests/ui/option_env_unwrap.stderr | 14 +- tests/ui/option_filter_map.stderr | 16 +- tests/ui/option_if_let_else.stderr | 50 +- tests/ui/option_map_or_err_ok.stderr | 2 +- tests/ui/option_map_or_none.stderr | 10 +- tests/ui/option_map_unit_fn_fixable.stderr | 38 +- tests/ui/option_map_unit_fn_unfixable.stderr | 8 +- tests/ui/option_option.stderr | 26 +- tests/ui/or_fun_call.stderr | 62 +-- tests/ui/or_then_unwrap.stderr | 6 +- .../out_of_bounds_indexing/issue-3102.stderr | 4 +- tests/ui/out_of_bounds_indexing/simple.stderr | 12 +- tests/ui/overflow_check_conditional.stderr | 16 +- tests/ui/overly_complex_bool_expr.stderr | 20 +- tests/ui/panic_in_result_fn.stderr | 8 +- tests/ui/panic_in_result_fn_assertions.stderr | 12 +- tests/ui/panicking_macros.stderr | 32 +- tests/ui/partial_pub_fields.stderr | 8 +- tests/ui/partialeq_ne_impl.stderr | 2 +- tests/ui/partialeq_to_none.stderr | 30 +- tests/ui/path_buf_push_overwrite.stderr | 2 +- tests/ui/path_ends_with_ext.stderr | 4 +- .../pattern_type_mismatch/mutability.stderr | 4 +- .../pattern_alternatives.stderr | 6 +- .../pattern_structs.stderr | 16 +- .../pattern_tuples.stderr | 20 +- tests/ui/pattern_type_mismatch/syntax.stderr | 18 +- tests/ui/patterns.stderr | 6 +- .../ui/permissions_set_readonly_false.stderr | 2 +- tests/ui/precedence.stderr | 24 +- tests/ui/print.stderr | 16 +- tests/ui/print_in_format_impl.stderr | 14 +- tests/ui/print_literal.stderr | 32 +- tests/ui/print_stderr.stderr | 4 +- tests/ui/print_with_newline.stderr | 18 +- tests/ui/println_empty_string.stderr | 8 +- tests/ui/proc_macro.stderr | 2 +- tests/ui/ptr_arg.stderr | 48 +- tests/ui/ptr_as_ptr.stderr | 66 +-- tests/ui/ptr_cast_constness.stderr | 14 +- tests/ui/ptr_eq.stderr | 4 +- tests/ui/ptr_eq_no_std.stderr | 4 +- tests/ui/ptr_offset_with_cast.stderr | 4 +- tests/ui/pub_use.stderr | 2 +- tests/ui/pub_with_shorthand.stderr | 8 +- tests/ui/pub_without_shorthand.stderr | 6 +- tests/ui/question_mark.stderr | 32 +- tests/ui/question_mark_used.stderr | 2 +- tests/ui/range.stderr | 2 +- tests/ui/range_contains.stderr | 42 +- tests/ui/range_plus_minus_one.stderr | 18 +- tests/ui/rc_buffer.stderr | 16 +- tests/ui/rc_buffer_arc.stderr | 16 +- tests/ui/rc_clone_in_vec_init/arc.stderr | 8 +- tests/ui/rc_clone_in_vec_init/rc.stderr | 8 +- tests/ui/rc_clone_in_vec_init/weak.stderr | 16 +- tests/ui/rc_mutex.stderr | 8 +- tests/ui/read_line_without_trim.fixed | 13 + tests/ui/read_line_without_trim.rs | 13 + tests/ui/read_line_without_trim.stderr | 70 ++- tests/ui/read_zero_byte_vec.stderr | 22 +- tests/ui/readonly_write_lock.stderr | 4 +- tests/ui/recursive_format_impl.stderr | 20 +- tests/ui/redundant_allocation.stderr | 40 +- tests/ui/redundant_allocation_fixable.stderr | 24 +- tests/ui/redundant_as_str.stderr | 4 +- tests/ui/redundant_async_block.stderr | 20 +- tests/ui/redundant_at_rest_pattern.stderr | 12 +- tests/ui/redundant_clone.stderr | 60 +- tests/ui/redundant_closure_call_early.stderr | 4 +- .../ui/redundant_closure_call_fixable.stderr | 34 +- tests/ui/redundant_closure_call_late.stderr | 6 +- tests/ui/redundant_else.stderr | 14 +- tests/ui/redundant_field_names.stderr | 16 +- tests/ui/redundant_guards.fixed | 57 +- tests/ui/redundant_guards.rs | 57 +- tests/ui/redundant_guards.stderr | 98 +++- tests/ui/redundant_locals.stderr | 56 +- ...dundant_pattern_matching_drop_order.stderr | 44 +- ...undant_pattern_matching_if_let_true.stderr | 14 +- .../redundant_pattern_matching_ipaddr.stderr | 40 +- .../redundant_pattern_matching_option.stderr | 60 +- .../ui/redundant_pattern_matching_poll.stderr | 40 +- .../redundant_pattern_matching_result.stderr | 56 +- tests/ui/redundant_pub_crate.stderr | 32 +- tests/ui/redundant_slicing.stderr | 6 +- tests/ui/redundant_static_lifetimes.stderr | 36 +- ...redundant_static_lifetimes_multiple.stderr | 20 +- tests/ui/redundant_type_annotations.stderr | 34 +- tests/ui/ref_as_ptr.fixed | 88 +-- tests/ui/ref_as_ptr.rs | 88 +-- tests/ui/ref_as_ptr.stderr | 244 ++++----- tests/ui/ref_binding_to_reference.stderr | 14 +- tests/ui/ref_option_ref.stderr | 22 +- tests/ui/ref_patterns.stderr | 6 +- tests/ui/regex.stderr | 48 +- tests/ui/rename.stderr | 116 ++-- tests/ui/renamed_builtin_attr.stderr | 2 +- tests/ui/repeat_once.stderr | 12 +- tests/ui/repeat_vec_with_capacity.stderr | 6 +- tests/ui/repl_uninit.stderr | 8 +- tests/ui/reserve_after_initialization.stderr | 6 +- .../ui/rest_pat_in_fully_bound_structs.stderr | 6 +- tests/ui/result_filter_map.stderr | 8 +- tests/ui/result_large_err.stderr | 24 +- tests/ui/result_map_or_into_option.stderr | 6 +- tests/ui/result_map_unit_fn_fixable.stderr | 36 +- tests/ui/result_map_unit_fn_unfixable.stderr | 12 +- tests/ui/result_unit_error.stderr | 10 +- tests/ui/return_self_not_must_use.stderr | 6 +- tests/ui/reversed_empty_ranges_fixable.stderr | 8 +- ...reversed_empty_ranges_loops_fixable.stderr | 12 +- ...versed_empty_ranges_loops_unfixable.stderr | 4 +- .../ui/reversed_empty_ranges_unfixable.stderr | 6 +- .../ui/same_functions_in_if_condition.stderr | 26 +- tests/ui/same_item_push.stderr | 10 +- tests/ui/same_name_method.stderr | 24 +- tests/ui/search_is_some.stderr | 16 +- tests/ui/search_is_some_fixable_none.stderr | 86 +-- tests/ui/search_is_some_fixable_some.stderr | 94 ++-- tests/ui/seek_from_current.stderr | 2 +- .../ui/seek_to_start_instead_of_rewind.stderr | 6 +- tests/ui/self_assignment.stderr | 22 +- tests/ui/self_named_constructors.stderr | 2 +- tests/ui/semicolon_if_nothing_returned.fixed | 7 +- tests/ui/semicolon_if_nothing_returned.rs | 7 +- tests/ui/semicolon_if_nothing_returned.stderr | 10 +- tests/ui/semicolon_inside_block.stderr | 8 +- tests/ui/semicolon_outside_block.stderr | 8 +- tests/ui/serde.stderr | 2 +- tests/ui/shadow.stderr | 92 ++-- tests/ui/short_circuit_statement.stderr | 6 +- .../ui/should_impl_trait/method_list_1.stderr | 30 +- .../ui/should_impl_trait/method_list_2.stderr | 30 +- tests/ui/should_panic_without_expect.stderr | 4 +- tests/ui/significant_drop_in_scrutinee.stderr | 52 +- tests/ui/significant_drop_tightening.stderr | 8 +- tests/ui/similar_names.rs | 5 +- tests/ui/similar_names.stderr | 50 +- tests/ui/single_call_fn.rs | 22 + tests/ui/single_call_fn.stderr | 76 ++- tests/ui/single_char_add_str.stderr | 30 +- tests/ui/single_char_lifetime_names.stderr | 10 +- tests/ui/single_char_pattern.stderr | 80 +-- tests/ui/single_component_path_imports.stderr | 4 +- ...component_path_imports_nested_first.stderr | 6 +- tests/ui/single_element_loop.stderr | 14 +- tests/ui/single_match.stderr | 36 +- tests/ui/single_match_else.stderr | 18 +- tests/ui/single_range_in_vec_init.stderr | 20 +- .../expressions.stderr | 8 +- .../size_of_in_element_count/functions.stderr | 42 +- tests/ui/size_of_ref.stderr | 6 +- tests/ui/skip_while_next.stderr | 4 +- tests/ui/slow_vector_initialization.stderr | 26 +- tests/ui/stable_sort_primitive.stderr | 14 +- tests/ui/starts_ends_with.stderr | 32 +- tests/ui/std_instead_of_core.stderr | 22 +- tests/ui/str_split.stderr | 20 +- tests/ui/str_to_string.stderr | 4 +- tests/ui/string_add.stderr | 8 +- tests/ui/string_add_assign.stderr | 6 +- tests/ui/string_extend.stderr | 8 +- tests/ui/string_from_utf8_as_bytes.stderr | 2 +- tests/ui/string_lit_as_bytes.stderr | 14 +- tests/ui/string_lit_chars_any.stderr | 10 +- tests/ui/string_slice.stderr | 6 +- tests/ui/string_to_string.stderr | 2 +- tests/ui/strlen_on_c_strings.stderr | 14 +- tests/ui/struct_excessive_bools.stderr | 4 +- tests/ui/struct_fields.rs | 8 +- tests/ui/struct_fields.stderr | 50 +- tests/ui/suspicious_arithmetic_impl.stderr | 18 +- tests/ui/suspicious_command_arg_space.stderr | 4 +- tests/ui/suspicious_doc_comments.stderr | 18 +- .../suspicious_doc_comments_unfixable.stderr | 4 +- tests/ui/suspicious_else_formatting.stderr | 18 +- tests/ui/suspicious_map.stderr | 4 +- .../ui/suspicious_operation_groupings.stderr | 52 +- tests/ui/suspicious_splitn.stderr | 18 +- tests/ui/suspicious_to_owned.stderr | 12 +- .../ui/suspicious_unary_op_formatting.stderr | 8 +- tests/ui/suspicious_xor_used_as_pow.stderr | 14 +- tests/ui/swap.stderr | 34 +- tests/ui/swap_ptr_to_ref.stderr | 8 +- tests/ui/swap_ptr_to_ref_unfixable.stderr | 6 +- tests/ui/tabs_in_doc_comments.stderr | 16 +- tests/ui/temporary_assignment.stderr | 8 +- tests/ui/test_attr_in_doctest.stderr | 6 +- tests/ui/tests_outside_test_module.stderr | 2 +- ...local_initializer_can_be_made_const.stderr | 8 +- tests/ui/to_digit_is_some.stderr | 4 +- ...to_string_in_format_args_incremental.fixed | 8 - tests/ui/to_string_trait_impl.rs | 44 ++ tests/ui/to_string_trait_impl.stderr | 16 +- tests/ui/toplevel_ref_arg.stderr | 12 +- tests/ui/toplevel_ref_arg_non_rustfix.stderr | 4 +- tests/ui/track-diagnostics.stderr | 2 +- tests/ui/trailing_empty_array.stderr | 22 +- tests/ui/trailing_zeros.stderr | 4 +- tests/ui/trait_duplication_in_bounds.stderr | 20 +- .../trait_duplication_in_bounds_unfixable.rs | 1 + ...ait_duplication_in_bounds_unfixable.stderr | 18 +- tests/ui/transmute.stderr | 72 +-- tests/ui/transmute_32bit.stderr | 8 +- tests/ui/transmute_64bit.stderr | 4 +- tests/ui/transmute_collection.stderr | 36 +- tests/ui/transmute_float_to_int.stderr | 12 +- tests/ui/transmute_int_to_char.stderr | 4 +- tests/ui/transmute_int_to_char_no_std.stderr | 4 +- tests/ui/transmute_int_to_non_zero.stderr | 20 +- tests/ui/transmute_null_to_fn.stderr | 12 +- tests/ui/transmute_ptr_to_ptr.stderr | 14 +- tests/ui/transmute_ptr_to_ref.stderr | 44 +- tests/ui/transmute_ref_to_ref.stderr | 8 +- tests/ui/transmute_ref_to_ref_no_std.stderr | 8 +- tests/ui/transmute_undefined_repr.stderr | 24 +- ...transmutes_expressible_as_ptr_casts.stderr | 20 +- tests/ui/transmuting_null.stderr | 6 +- tests/ui/trim_split_whitespace.stderr | 16 +- tests/ui/trivially_copy_pass_by_ref.stderr | 38 +- tests/ui/try_err.stderr | 24 +- tests/ui/tuple_array_conversions.stderr | 20 +- tests/ui/type_complexity.stderr | 30 +- tests/ui/type_id_on_box.stderr | 6 +- tests/ui/type_repetition_in_bounds.rs | 2 +- tests/ui/type_repetition_in_bounds.stderr | 12 +- tests/ui/types.stderr | 2 +- .../ui/unchecked_duration_subtraction.stderr | 8 +- tests/ui/unconditional_recursion.rs | 2 +- tests/ui/unconditional_recursion.stderr | 91 ++-- tests/ui/unicode.stderr | 20 +- tests/ui/uninhabited_references.stderr | 8 +- tests/ui/uninit.stderr | 6 +- tests/ui/uninit_vec.stderr | 22 +- tests/ui/uninlined_format_args.stderr | 142 ++--- ...lined_format_args_panic.edition2018.stderr | 2 +- ...lined_format_args_panic.edition2021.stderr | 12 +- tests/ui/unit_arg.stderr | 20 +- tests/ui/unit_arg_empty_blocks.stderr | 8 +- tests/ui/unit_cmp.stderr | 12 +- tests/ui/unit_hash.stderr | 6 +- tests/ui/unit_return_expecting_ord.stderr | 12 +- tests/ui/unknown_attribute.stderr | 2 +- tests/ui/unknown_clippy_lints.stderr | 18 +- tests/ui/unnecessary_box_returns.stderr | 8 +- tests/ui/unnecessary_cast.fixed | 1 + tests/ui/unnecessary_cast.rs | 1 + tests/ui/unnecessary_cast.stderr | 80 +-- tests/ui/unnecessary_cast_unfixable.stderr | 4 +- tests/ui/unnecessary_clippy_cfg.rs | 23 + tests/ui/unnecessary_clippy_cfg.stderr | 61 +++ tests/ui/unnecessary_clone.stderr | 18 +- .../ui/unnecessary_fallible_conversions.fixed | 37 ++ tests/ui/unnecessary_fallible_conversions.rs | 37 ++ .../unnecessary_fallible_conversions.stderr | 124 ++++- ...sary_fallible_conversions_unfixable.stderr | 12 +- tests/ui/unnecessary_filter_map.stderr | 10 +- tests/ui/unnecessary_find_map.stderr | 10 +- tests/ui/unnecessary_fold.stderr | 32 +- tests/ui/unnecessary_get_then_check.fixed | 26 + tests/ui/unnecessary_get_then_check.rs | 26 + tests/ui/unnecessary_get_then_check.stderr | 75 +++ tests/ui/unnecessary_iter_cloned.stderr | 4 +- tests/ui/unnecessary_join.stderr | 4 +- tests/ui/unnecessary_lazy_eval.stderr | 126 ++--- .../ui/unnecessary_lazy_eval_unfixable.stderr | 8 +- tests/ui/unnecessary_literal_unwrap.stderr | 106 ++-- ...nnecessary_literal_unwrap_unfixable.stderr | 204 +++---- .../ui/unnecessary_map_on_constructor.stderr | 16 +- tests/ui/unnecessary_operation.stderr | 38 +- .../ui/unnecessary_owned_empty_strings.stderr | 4 +- .../ui/unnecessary_result_map_or_else.stderr | 8 +- tests/ui/unnecessary_safety_comment.stderr | 36 +- tests/ui/unnecessary_self_imports.stderr | 4 +- tests/ui/unnecessary_sort_by.stderr | 24 +- .../unnecessary_struct_initialization.stderr | 12 +- tests/ui/unnecessary_to_owned.fixed | 36 ++ tests/ui/unnecessary_to_owned.rs | 36 ++ tests/ui/unnecessary_to_owned.stderr | 202 ++++--- tests/ui/unnecessary_to_owned_on_split.stderr | 18 +- tests/ui/unnecessary_unsafety_doc.stderr | 14 +- tests/ui/unnecessary_wraps.stderr | 14 +- tests/ui/unneeded_field_pattern.stderr | 4 +- tests/ui/unneeded_wildcard_pattern.stderr | 30 +- tests/ui/unnested_or_patterns.stderr | 34 +- tests/ui/unnested_or_patterns2.stderr | 16 +- tests/ui/unreadable_literal.stderr | 20 +- tests/ui/unsafe_derive_deserialize.stderr | 8 +- tests/ui/unsafe_removed_from_name.stderr | 10 +- tests/ui/unseparated_prefix_literals.stderr | 18 +- tests/ui/unused_async.stderr | 10 +- tests/ui/unused_enumerate_index.stderr | 4 +- tests/ui/unused_format_specs_unfixable.stderr | 8 +- tests/ui/unused_io_amount.stderr | 70 +-- tests/ui/unused_peekable.stderr | 16 +- tests/ui/unused_rounding.stderr | 10 +- tests/ui/unused_self.stderr | 18 +- tests/ui/unused_unit.fixed | 7 + tests/ui/unused_unit.rs | 7 + tests/ui/unused_unit.stderr | 40 +- tests/ui/unwrap.stderr | 6 +- tests/ui/unwrap_expect_used.stderr | 12 +- tests/ui/unwrap_in_result.stderr | 8 +- tests/ui/unwrap_or.stderr | 4 +- tests/ui/unwrap_or_else_default.stderr | 32 +- tests/ui/upper_case_acronyms.stderr | 24 +- tests/ui/use_self.stderr | 84 +-- tests/ui/use_self_trait.stderr | 32 +- tests/ui/used_underscore_binding.stderr | 24 +- tests/ui/useless_asref.stderr | 38 +- tests/ui/useless_attribute.fixed | 10 +- tests/ui/useless_attribute.rs | 10 +- tests/ui/useless_attribute.stderr | 10 +- tests/ui/useless_conversion.stderr | 76 +-- tests/ui/useless_conversion_try.stderr | 20 +- tests/ui/vec.fixed | 4 + tests/ui/vec.rs | 4 + tests/ui/vec.stderr | 48 +- tests/ui/vec_box_sized.stderr | 18 +- tests/ui/vec_init_then_push.stderr | 16 +- tests/ui/vec_resize_to_zero.stderr | 2 +- tests/ui/verbose_file_reads.stderr | 4 +- tests/ui/waker_clone_wake.stderr | 4 +- tests/ui/while_let_loop.stderr | 10 +- tests/ui/while_let_on_iterator.stderr | 54 +- tests/ui/wild_in_or_pats.stderr | 8 +- tests/ui/wildcard_enum_match_arm.stderr | 14 +- tests/ui/wildcard_imports.stderr | 44 +- .../wildcard_imports_2021.edition2018.stderr | 44 +- .../wildcard_imports_2021.edition2021.stderr | 44 +- tests/ui/write_literal.stderr | 24 +- tests/ui/write_literal_2.stderr | 28 +- tests/ui/write_with_newline.stderr | 18 +- tests/ui/writeln_empty_string.stderr | 4 +- tests/ui/wrong_self_convention.stderr | 48 +- tests/ui/wrong_self_convention2.stderr | 4 +- tests/ui/wrong_self_conventions_mut.stderr | 4 +- tests/ui/zero_div_zero.stderr | 8 +- tests/ui/zero_offset.stderr | 16 +- tests/ui/zero_ptr.stderr | 10 +- tests/ui/zero_ptr_no_std.stderr | 8 +- tests/ui/zero_sized_btreemap_values.stderr | 26 +- tests/ui/zero_sized_hashmap_values.stderr | 26 +- triagebot.toml | 4 +- util/gh-pages/index.html | 14 +- 1096 files changed, 14122 insertions(+), 10811 deletions(-) create mode 100644 clippy_lints/src/methods/unnecessary_get_then_check.rs create mode 100644 clippy_lints/src/multiple_bound_locations.rs create mode 100644 tests/ui-toml/disallowed_macros/auxiliary/proc_macros.rs create mode 100644 tests/ui/asm_syntax_not_x86.rs rename tests/ui/{asm_syntax.stderr => asm_syntax_x86.i686.stderr} (58%) rename tests/ui/{asm_syntax.rs => asm_syntax_x86.rs} (64%) create mode 100644 tests/ui/asm_syntax_x86.x86_64.stderr create mode 100644 tests/ui/cfg_attr_cargo_clippy.fixed create mode 100644 tests/ui/cfg_attr_cargo_clippy.rs create mode 100644 tests/ui/cfg_attr_cargo_clippy.stderr create mode 100644 tests/ui/crashes/ice-12253.rs create mode 100644 tests/ui/empty_docs.rs create mode 100644 tests/ui/empty_docs.stderr create mode 100644 tests/ui/multiple_bound_locations.rs create mode 100644 tests/ui/multiple_bound_locations.stderr create mode 100644 tests/ui/no_effect_async_fn.rs create mode 100644 tests/ui/no_effect_async_fn.stderr delete mode 100644 tests/ui/to_string_in_format_args_incremental.fixed create mode 100644 tests/ui/unnecessary_clippy_cfg.rs create mode 100644 tests/ui/unnecessary_clippy_cfg.stderr create mode 100644 tests/ui/unnecessary_get_then_check.fixed create mode 100644 tests/ui/unnecessary_get_then_check.rs create mode 100644 tests/ui/unnecessary_get_then_check.stderr diff --git a/.github/driver.sh b/.github/driver.sh index 40a2aad0f5379..11fd6b5c79ed8 100755 --- a/.github/driver.sh +++ b/.github/driver.sh @@ -32,7 +32,7 @@ test "$sysroot" = $desired_sysroot ) # Check that the --sysroot argument is only passed once via arg_file.txt (SYSROOT is ignored) -( +( echo "fn main() {}" > target/driver_test.rs echo "--sysroot="$(./target/debug/clippy-driver --print sysroot)"" > arg_file.txt echo "--verbose" >> arg_file.txt @@ -45,7 +45,7 @@ unset CARGO_MANIFEST_DIR # Run a lint and make sure it produces the expected output. It's also expected to exit with code 1 # FIXME: How to match the clippy invocation in compile-test.rs? ./target/debug/clippy-driver -Dwarnings -Aunused -Zui-testing --emit metadata --crate-type bin tests/ui/double_neg.rs 2>double_neg.stderr && exit 1 -sed -e "s,tests/ui,\$DIR," -e "/= help: for/d" double_neg.stderr > normalized.stderr +sed -e "/= help: for/d" double_neg.stderr > normalized.stderr diff -u normalized.stderr tests/ui/double_neg.stderr # make sure "clippy-driver --rustc --arg" and "rustc --arg" behave the same diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b853567219c9..f0b01742deb05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5125,6 +5125,7 @@ Released 2018-09-13 [`default_trait_access`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_trait_access [`default_union_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_union_representation [`deprecated_cfg_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr +[`deprecated_clippy_cfg_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_clippy_cfg_attr [`deprecated_semver`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_semver [`deref_addrof`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_addrof [`deref_by_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_by_slicing @@ -5157,6 +5158,7 @@ Released 2018-09-13 [`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec [`eager_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#eager_transmute [`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else +[`empty_docs`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_docs [`empty_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_drop [`empty_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum [`empty_enum_variants_with_brackets`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum_variants_with_brackets @@ -5429,6 +5431,7 @@ Released 2018-09-13 [`modulo_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_arithmetic [`modulo_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_one [`multi_assignments`]: https://rust-lang.github.io/rust-clippy/master/index.html#multi_assignments +[`multiple_bound_locations`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_bound_locations [`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions [`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl [`multiple_unsafe_ops_per_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_unsafe_ops_per_block @@ -5725,10 +5728,12 @@ Released 2018-09-13 [`unknown_clippy_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#unknown_clippy_lints [`unnecessary_box_returns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns [`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast +[`unnecessary_clippy_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_clippy_cfg [`unnecessary_fallible_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fallible_conversions [`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map [`unnecessary_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_find_map [`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold +[`unnecessary_get_then_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_get_then_check [`unnecessary_join`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_join [`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations [`unnecessary_literal_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_unwrap diff --git a/Cargo.toml b/Cargo.toml index 321424880d1e2..5d1d0ce2c42fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,17 +27,17 @@ rustc_tools_util = "0.3.0" tempfile = { version = "3.2", optional = true } termize = "0.1" color-print = "0.3.4" -anstream = "0.5.0" +anstream = "0.6.0" [dev-dependencies] -ui_test = "0.21.2" +ui_test = "0.22.2" tester = "0.9" regex = "1.5" toml = "0.7.3" walkdir = "2.3" # This is used by the `collect-metadata` alias. filetime = "0.2" -itertools = "0.11" +itertools = "0.12" # UI test dependencies clippy_utils = { path = "clippy_utils" } diff --git a/book/src/configuration.md b/book/src/configuration.md index e8274bc4575d0..9eb067abd91ec 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -33,26 +33,29 @@ disallowed-names = ["bar", ".."] # -> ["bar", "foo", "baz", "quux"] To deactivate the "for further information visit *lint-link*" message you can define the `CLIPPY_DISABLE_DOCS_LINKS` environment variable. -### Allowing/denying lints +### Allowing/Denying Lints -You can add options to your code to `allow`/`warn`/`deny` Clippy lints: +#### Attributes in Code -* the whole set of `Warn` lints using the `clippy` lint group (`#![deny(clippy::all)]`) +You can add attributes to your code to `allow`/`warn`/`deny` Clippy lints: -* all lints using both the `clippy` and `clippy::pedantic` lint groups (`#![deny(clippy::all)]`, - `#![deny(clippy::pedantic)]`). Note that `clippy::pedantic` contains some very aggressive lints prone to false - positives. +* the whole set of `warn`-by-default lints using the `clippy` lint group (`#![allow(clippy::all)]`) + +* all lints using both the `clippy` and `clippy::pedantic` lint groups (`#![warn(clippy::all, clippy::pedantic)]`. Note + that `clippy::pedantic` contains some very aggressive lints prone to false positives. * only some lints (`#![deny(clippy::single_match, clippy::box_vec)]`, etc.) * `allow`/`warn`/`deny` can be limited to a single function or module using `#[allow(...)]`, etc. Note: `allow` means to suppress the lint for your code. With `warn` the lint will only emit a warning, while with `deny` -the lint will emit an error, when triggering for your code. An error causes clippy to exit with an error code, so is -useful in scripts like CI/CD. +the lint will emit an error, when triggering for your code. An error causes Clippy to exit with an error code, so is +most useful in scripts used in CI/CD. + +#### Command Line Flags -If you do not want to include your lint levels in your code, you can globally enable/disable lints by passing extra -flags to Clippy during the run: +If you do not want to include your lint levels in the code, you can globally enable/disable lints by passing extra flags +to Clippy during the run: To allow `lint_name`, run @@ -66,19 +69,33 @@ And to warn on `lint_name`, run cargo clippy -- -W clippy::lint_name ``` -This also works with lint groups. For example, you can run Clippy with warnings for all lints enabled: +This also works with lint groups. For example, you can run Clippy with warnings for all pedantic lints enabled: ```terminal cargo clippy -- -W clippy::pedantic ``` -If you care only about a single lint, you can allow all others and then explicitly warn on the lint(s) you are +If you care only about a certain lints, you can allow all others and then explicitly warn on the lints you are interested in: ```terminal cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::... ``` +#### Lints Section in `Cargo.toml` + +Finally, lints can be allowed/denied using [the lints +section](https://doc.rust-lang.org/nightly/cargo/reference/manifest.html#the-lints-section)) in the `Cargo.toml` file: + +To deny `clippy::enum_glob_use`, put the following in the `Cargo.toml`: + +```toml +[lints.clippy] +enum_glob_use = "deny" +``` + +For more details and options, refer to the Cargo documentation. + ### Specifying the minimum supported Rust version Projects that intend to support old versions of Rust can disable lints pertaining to newer features by specifying the @@ -113,17 +130,14 @@ found [here](https://rust-lang.github.io/rust-clippy/master/index.html#msrv) Very rarely, you may wish to prevent Clippy from evaluating certain sections of code entirely. You can do this with [conditional compilation](https://doc.rust-lang.org/reference/conditional-compilation.html) by checking that the -`cargo-clippy` feature is not set. You may need to provide a stub so that the code compiles: +`clippy` cfg is not set. You may need to provide a stub so that the code compiles: ```rust -#[cfg(not(feature = "cargo-clippy"))] +#[cfg(not(clippy)] include!(concat!(env!("OUT_DIR"), "/my_big_function-generated.rs")); -#[cfg(feature = "cargo-clippy")] +#[cfg(clippy)] fn my_big_function(_input: &str) -> Option { None } ``` - -This feature is not actually part of your crate, so specifying `--all-features` to other tools, e.g. `cargo test ---all-features`, will not disable it. diff --git a/book/src/development/emitting_lints.md b/book/src/development/emitting_lints.md index a12f6aa91b307..d70f4fc17ebf0 100644 --- a/book/src/development/emitting_lints.md +++ b/book/src/development/emitting_lints.md @@ -82,7 +82,7 @@ The output looks something like this (from the example earlier): ```text error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:37:14 + --> tests/ui/range_plus_minus_one.rs:37:14 | LL | for _ in 1..1 + 1 {} | ^^^^^^^^ help: use: `1..=1` @@ -135,14 +135,14 @@ Examples: ```text error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/drop_forget_ref.rs:10:5 + --> tests/ui/drop_forget_ref.rs:10:5 | 10 | forget(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::forget-ref` implied by `-D warnings` note: argument has type &SomeStruct - --> $DIR/drop_forget_ref.rs:10:12 + --> tests/ui/drop_forget_ref.rs:10:12 | 10 | forget(&SomeStruct); | ^^^^^^^^^^^ @@ -158,7 +158,7 @@ Example: ```text error: constant division of 0.0 with 0.0 will always result in NaN - --> $DIR/zero_div_zero.rs:6:25 + --> tests/ui/zero_div_zero.rs:6:25 | 6 | let other_f64_nan = 0.0f64 / 0.0; | ^^^^^^^^^^^^ @@ -176,7 +176,7 @@ Example: ```text error: This `.fold` can be more succinctly expressed as `.any` ---> $DIR/methods.rs:390:13 +--> tests/ui/methods.rs:390:13 | 390 | let _ = (0..3).fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)` diff --git a/book/src/development/writing_tests.md b/book/src/development/writing_tests.md index 8937e0d8e9469..39a5ad9668851 100644 --- a/book/src/development/writing_tests.md +++ b/book/src/development/writing_tests.md @@ -97,19 +97,19 @@ failures: ---- compile_test stdout ---- normalized stderr: error: function called "foo" - --> $DIR/foo_functions.rs:6:12 + --> tests/ui/foo_functions.rs:6:12 | LL | pub fn foo(&self) {} | ^^^ | = note: `-D clippy::foo-functions` implied by `-D warnings` error: function called "foo" - --> $DIR/foo_functions.rs:13:8 + --> tests/ui/foo_functions.rs:13:8 | LL | fn foo(&self) {} | ^^^ error: function called "foo" - --> $DIR/foo_functions.rs:19:4 + --> tests/ui/foo_functions.rs:19:4 | LL | fn foo() {} | ^^^ diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index f2357e2b5de92..214a60d3bfdf7 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -278,7 +278,7 @@ The minimum number of struct fields for the lints about field names to trigger --- **Affected lints:** -* [`struct_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#struct_variant_names) +* [`struct_field_names`](https://rust-lang.github.io/rust-clippy/master/index.html#struct_field_names) ## `enum-variant-size-threshold` diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 9741b94d50413..b781259ad9695 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -325,7 +325,7 @@ define_Conf! { /// /// The minimum number of enum variants for the lints about variant names to trigger (enum_variant_name_threshold: u64 = 3), - /// Lint: STRUCT_VARIANT_NAMES. + /// Lint: STRUCT_FIELD_NAMES. /// /// The minimum number of struct fields for the lints about field names to trigger (struct_field_name_threshold: u64 = 3), @@ -648,7 +648,7 @@ fn deserialize(file: &SourceFile) -> TryConf { extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS); extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES); // TODO: THIS SHOULD BE TESTED, this comment will be gone soon - if conf.conf.allowed_idents_below_min_chars.contains(&"..".to_owned()) { + if conf.conf.allowed_idents_below_min_chars.contains("..") { conf.conf .allowed_idents_below_min_chars .extend(DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string)); diff --git a/clippy_config/src/lib.rs b/clippy_config/src/lib.rs index 5449feed090a9..dab3119894a4d 100644 --- a/clippy_config/src/lib.rs +++ b/clippy_config/src/lib.rs @@ -6,7 +6,7 @@ clippy::missing_panics_doc, rustc::diagnostic_outside_of_impl, rustc::untranslatable_diagnostic, - rustc::untranslatable_diagnostic_trivial, + rustc::untranslatable_diagnostic_trivial )] extern crate rustc_ast; diff --git a/clippy_dev/Cargo.toml b/clippy_dev/Cargo.toml index 5ec67554e7d89..42a953039b1c0 100644 --- a/clippy_dev/Cargo.toml +++ b/clippy_dev/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" aho-corasick = "1.0" clap = "4.1.4" indoc = "1.0" -itertools = "0.11" +itertools = "0.12" opener = "0.6" shell-escape = "0.1" walkdir = "2.3" diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 6e6e315bb6561..6ae089b3e0321 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -14,7 +14,7 @@ cargo_metadata = "0.18" clippy_config = { path = "../clippy_config" } clippy_utils = { path = "../clippy_utils" } declare_clippy_lint = { path = "../declare_clippy_lint" } -itertools = "0.11" +itertools = "0.12" quine-mc_cluskey = "0.2" regex-syntax = "0.8" serde = { version = "1.0", features = ["derive"] } diff --git a/clippy_lints/src/asm_syntax.rs b/clippy_lints/src/asm_syntax.rs index feb6437ee26ac..c2fa56e136031 100644 --- a/clippy_lints/src/asm_syntax.rs +++ b/clippy_lints/src/asm_syntax.rs @@ -2,8 +2,11 @@ use std::fmt; use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Expr, ExprKind, InlineAsmOptions}; -use rustc_lint::{EarlyContext, EarlyLintPass, Lint}; +use rustc_ast::{InlineAsm, Item, ItemKind}; +use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext}; use rustc_session::declare_lint_pass; +use rustc_span::Span; +use rustc_target::asm::InlineAsmArch; #[derive(Clone, Copy, PartialEq, Eq)] enum AsmStyle { @@ -31,8 +34,14 @@ impl std::ops::Not for AsmStyle { } } -fn check_expr_asm_syntax(lint: &'static Lint, cx: &EarlyContext<'_>, expr: &Expr, check_for: AsmStyle) { - if let ExprKind::InlineAsm(ref inline_asm) = expr.kind { +fn check_asm_syntax( + lint: &'static Lint, + cx: &EarlyContext<'_>, + inline_asm: &InlineAsm, + span: Span, + check_for: AsmStyle, +) { + if matches!(cx.sess().asm_arch, Some(InlineAsmArch::X86 | InlineAsmArch::X86_64)) { let style = if inline_asm.options.contains(InlineAsmOptions::ATT_SYNTAX) { AsmStyle::Att } else { @@ -43,7 +52,7 @@ fn check_expr_asm_syntax(lint: &'static Lint, cx: &EarlyContext<'_>, expr: &Expr span_lint_and_help( cx, lint, - expr.span, + span, &format!("{style} x86 assembly syntax used"), None, &format!("use {} x86 assembly syntax", !style), @@ -89,7 +98,15 @@ declare_lint_pass!(InlineAsmX86IntelSyntax => [INLINE_ASM_X86_INTEL_SYNTAX]); impl EarlyLintPass for InlineAsmX86IntelSyntax { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - check_expr_asm_syntax(Self::get_lints()[0], cx, expr, AsmStyle::Intel); + if let ExprKind::InlineAsm(inline_asm) = &expr.kind { + check_asm_syntax(Self::get_lints()[0], 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(Self::get_lints()[0], cx, inline_asm, item.span, AsmStyle::Intel); + } } } @@ -130,6 +147,14 @@ declare_lint_pass!(InlineAsmX86AttSyntax => [INLINE_ASM_X86_ATT_SYNTAX]); impl EarlyLintPass for InlineAsmX86AttSyntax { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - check_expr_asm_syntax(Self::get_lints()[0], cx, expr, AsmStyle::Att); + if let ExprKind::InlineAsm(inline_asm) = &expr.kind { + check_asm_syntax(Self::get_lints()[0], cx, inline_asm, expr.span, AsmStyle::Att); + } + } + + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + if let ItemKind::GlobalAsm(inline_asm) = &item.kind { + check_asm_syntax(Self::get_lints()[0], cx, inline_asm, item.span, AsmStyle::Att); + } } } diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index da38422874b44..f2937d51340b8 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -1,7 +1,9 @@ //! checks for attributes use clippy_config::msrvs::{self, Msrv}; -use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::diagnostics::{ + span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, +}; use clippy_utils::is_from_proc_macro; use clippy_utils::macros::{is_panic, macro_backtrace}; use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments}; @@ -433,6 +435,56 @@ declare_clippy_lint! { "prevent from misusing the wrong attr name" } +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. + /// + /// ### Example + /// ```no_run + /// #[cfg(feature = "cargo-clippy")] + /// struct Bar; + /// ``` + /// + /// Use instead: + /// ```no_run + /// #[cfg(clippy)] + /// struct Bar; + /// ``` + #[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 `#[cfg_attr(clippy, allow(clippy::lint))]` + /// and suggests to replace it with `#[allow(clippy::lint)]`. + /// + /// ### Why is this bad? + /// There is no reason to put clippy attributes behind a clippy `cfg` as they are not + /// run by anything else than clippy. + /// + /// ### Example + /// ```no_run + /// #![cfg_attr(clippy, allow(clippy::deprecated_cfg_attr))] + /// ``` + /// + /// Use instead: + /// ```no_run + /// #![allow(clippy::deprecated_cfg_attr)] + /// ``` + #[clippy::version = "1.78.0"] + pub UNNECESSARY_CLIPPY_CFG, + suspicious, + "usage of `cfg_attr(clippy, allow(clippy::lint))` instead of `allow(clippy::lint)`" +} + declare_lint_pass!(Attributes => [ ALLOW_ATTRIBUTES_WITHOUT_REASON, INLINE_ALWAYS, @@ -512,6 +564,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { || is_word(lint, sym::deprecated) || is_word(lint, sym!(unreachable_pub)) || is_word(lint, sym!(unused)) + || is_word(lint, sym!(unused_import_braces)) || extract_clippy_lint(lint).map_or(false, |s| { matches!( s.as_str(), @@ -794,6 +847,8 @@ impl_lint_pass!(EarlyAttributes => [ EMPTY_LINE_AFTER_DOC_COMMENTS, NON_MINIMAL_CFG, MAYBE_MISUSED_CFG, + DEPRECATED_CLIPPY_CFG_ATTR, + UNNECESSARY_CLIPPY_CFG, ]); impl EarlyLintPass for EarlyAttributes { @@ -803,6 +858,7 @@ impl EarlyLintPass for EarlyAttributes { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { check_deprecated_cfg_attr(cx, attr, &self.msrv); + check_deprecated_cfg(cx, attr); check_mismatched_target_os(cx, attr); check_minimal_cfg_condition(cx, attr); check_misused_cfg(cx, attr); @@ -857,39 +913,146 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It } } +fn check_cargo_clippy_attr(cx: &EarlyContext<'_>, item: &rustc_ast::MetaItem) { + if item.has_name(sym::feature) && item.value_str().is_some_and(|v| v.as_str() == "cargo-clippy") { + span_lint_and_sugg( + cx, + DEPRECATED_CLIPPY_CFG_ATTR, + item.span, + "`feature = \"cargo-clippy\"` was replaced by `clippy`", + "replace with", + "clippy".to_string(), + Applicability::MachineApplicable, + ); + } +} + +fn check_deprecated_cfg_recursively(cx: &EarlyContext<'_>, attr: &rustc_ast::MetaItem) { + if let Some(ident) = attr.ident() { + if ["any", "all", "not"].contains(&ident.name.as_str()) { + let Some(list) = attr.meta_item_list() else { return }; + for item in list.iter().filter_map(|item| item.meta_item()) { + check_deprecated_cfg_recursively(cx, item); + } + } else { + check_cargo_clippy_attr(cx, attr); + } + } +} + +fn check_deprecated_cfg(cx: &EarlyContext<'_>, attr: &Attribute) { + if attr.has_name(sym::cfg) + && let Some(list) = attr.meta_item_list() + { + for item in list.iter().filter_map(|item| item.meta_item()) { + check_deprecated_cfg_recursively(cx, item); + } + } +} + fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &Msrv) { - if msrv.meets(msrvs::TOOL_ATTRIBUTES) - // check cfg_attr - && attr.has_name(sym::cfg_attr) + // check cfg_attr + if attr.has_name(sym::cfg_attr) && let Some(items) = attr.meta_item_list() && items.len() == 2 - // check for `rustfmt` && let Some(feature_item) = items[0].meta_item() - && feature_item.has_name(sym::rustfmt) - // check for `rustfmt_skip` and `rustfmt::skip` - && let Some(skip_item) = &items[1].meta_item() - && (skip_item.has_name(sym!(rustfmt_skip)) - || skip_item - .path - .segments - .last() - .expect("empty path in attribute") - .ident - .name - == sym::skip) - // Only lint outer attributes, because custom inner attributes are unstable - // Tracking issue: https://github.com/rust-lang/rust/issues/54726 - && attr.style == AttrStyle::Outer { - span_lint_and_sugg( - cx, - DEPRECATED_CFG_ATTR, - attr.span, - "`cfg_attr` is deprecated for rustfmt and got replaced by tool attributes", - "use", - "#[rustfmt::skip]".to_string(), - Applicability::MachineApplicable, - ); + // check for `rustfmt` + if feature_item.has_name(sym::rustfmt) + && msrv.meets(msrvs::TOOL_ATTRIBUTES) + // check for `rustfmt_skip` and `rustfmt::skip` + && let Some(skip_item) = &items[1].meta_item() + && (skip_item.has_name(sym!(rustfmt_skip)) + || skip_item + .path + .segments + .last() + .expect("empty path in attribute") + .ident + .name + == sym::skip) + // Only lint outer attributes, because custom inner attributes are unstable + // Tracking issue: https://github.com/rust-lang/rust/issues/54726 + && attr.style == AttrStyle::Outer + { + span_lint_and_sugg( + cx, + DEPRECATED_CFG_ATTR, + attr.span, + "`cfg_attr` is deprecated for rustfmt and got replaced by tool attributes", + "use", + "#[rustfmt::skip]".to_string(), + Applicability::MachineApplicable, + ); + } else { + check_deprecated_cfg_recursively(cx, feature_item); + if let Some(behind_cfg_attr) = items[1].meta_item() { + check_clippy_cfg_attr(cx, feature_item, behind_cfg_attr, attr); + } + } + } +} + +fn check_clippy_cfg_attr( + cx: &EarlyContext<'_>, + cfg_attr: &rustc_ast::MetaItem, + behind_cfg_attr: &rustc_ast::MetaItem, + attr: &Attribute, +) { + if cfg_attr.has_name(sym::clippy) + && let Some(ident) = behind_cfg_attr.ident() + && Level::from_symbol(ident.name, Some(attr.id)).is_some() + && let Some(items) = behind_cfg_attr.meta_item_list() + { + let nb_items = items.len(); + let mut clippy_lints = Vec::with_capacity(items.len()); + for item in items { + if let Some(meta_item) = item.meta_item() + && let [part1, _] = meta_item.path.segments.as_slice() + && part1.ident.name == sym::clippy + { + clippy_lints.push(item.span()); + } + } + if clippy_lints.is_empty() { + return; + } + if nb_items == clippy_lints.len() { + if let Some(snippet) = snippet_opt(cx, behind_cfg_attr.span) { + span_lint_and_sugg( + cx, + UNNECESSARY_CLIPPY_CFG, + attr.span, + "no need to put clippy lints behind a `clippy` cfg", + "replace with", + format!( + "#{}[{}]", + if attr.style == AttrStyle::Inner { "!" } else { "" }, + snippet + ), + Applicability::MachineApplicable, + ); + } + } else { + let snippet = clippy_lints + .iter() + .filter_map(|sp| snippet_opt(cx, *sp)) + .collect::>() + .join(","); + span_lint_and_note( + cx, + UNNECESSARY_CLIPPY_CFG, + clippy_lints, + "no need to put clippy lints behind a `clippy` cfg", + None, + &format!( + "write instead: `#{}[{}({})]`", + if attr.style == AttrStyle::Inner { "!" } else { "" }, + ident.name, + snippet + ), + ); + } } } diff --git a/clippy_lints/src/blocks_in_conditions.rs b/clippy_lints/src/blocks_in_conditions.rs index ff4dffd06079f..2eb0dac974258 100644 --- a/clippy_lints/src/blocks_in_conditions.rs +++ b/clippy_lints/src/blocks_in_conditions.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::snippet_block_with_applicability; use clippy_utils::ty::implements_trait; use clippy_utils::visitors::{for_each_expr, Descend}; -use clippy_utils::{get_parent_expr, higher}; +use clippy_utils::{get_parent_expr, higher, is_from_proc_macro}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::{BlockCheckMode, Expr, ExprKind, MatchSource}; @@ -13,7 +13,7 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Checks for `if` conditions that use blocks containing an + /// Checks for `if` and `match` conditions that use blocks containing an /// expression, statements or conditions that use closures with blocks. /// /// ### Why is this bad? @@ -25,6 +25,11 @@ declare_clippy_lint! { /// if { true } { /* ... */ } /// /// if { let x = somefunc(); x } { /* ... */ } + /// + /// match { let e = somefunc(); e } { + /// // ... + /// # _ => {} + /// } /// ``` /// /// Use instead: @@ -34,6 +39,12 @@ declare_clippy_lint! { /// /// let res = { let x = somefunc(); x }; /// if res { /* ... */ } + /// + /// let res = { let e = somefunc(); e }; + /// match res { + /// // ... + /// # _ => {} + /// } /// ``` #[clippy::version = "1.45.0"] pub BLOCKS_IN_CONDITIONS, @@ -94,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInConditions { } } else { let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span); - if span.from_expansion() || expr.span.from_expansion() { + if span.from_expansion() || expr.span.from_expansion() || is_from_proc_macro(cx, cond) { return; } // move block higher diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 2d1c250ace905..0d66f2d644d98 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -85,7 +85,117 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool { ) { NonminimalBoolVisitor { cx }.visit_body(body); } + + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + match expr.kind { + ExprKind::Unary(UnOp::Not, sub) => check_inverted_condition(cx, expr.span, sub), + // This check the case where an element in a boolean comparison is inverted, like: + // + // ``` + // let a = true; + // !a == false; + // ``` + ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq | BinOpKind::Ne) => { + check_inverted_bool_in_condition(cx, expr.span, op.node, left, right); + }, + _ => {}, + } + } +} + +fn inverted_bin_op_eq_str(op: BinOpKind) -> Option<&'static str> { + match op { + BinOpKind::Eq => Some("!="), + BinOpKind::Ne => Some("=="), + _ => None, + } +} + +fn bin_op_eq_str(op: BinOpKind) -> Option<&'static str> { + match op { + BinOpKind::Eq => Some("=="), + BinOpKind::Ne => Some("!="), + _ => None, + } +} + +fn check_inverted_condition(cx: &LateContext<'_>, expr_span: Span, sub_expr: &Expr<'_>) { + if !expr_span.from_expansion() + && let ExprKind::Binary(op, left, right) = sub_expr.kind + && let Some(left) = snippet_opt(cx, left.span) + && let Some(right) = snippet_opt(cx, right.span) + { + let Some(op) = inverted_bin_op_eq_str(op.node) else { + return; + }; + span_lint_and_sugg( + cx, + NONMINIMAL_BOOL, + expr_span, + "this boolean expression can be simplified", + "try", + format!("{left} {op} {right}",), + Applicability::MachineApplicable, + ); + } +} + +fn check_inverted_bool_in_condition( + cx: &LateContext<'_>, + expr_span: Span, + op: BinOpKind, + left: &Expr<'_>, + right: &Expr<'_>, +) { + if expr_span.from_expansion() + && (!cx.typeck_results().node_types()[left.hir_id].is_bool() + || !cx.typeck_results().node_types()[right.hir_id].is_bool()) + { + return; + } + + let suggestion = match (left.kind, right.kind) { + (ExprKind::Unary(UnOp::Not, left_sub), ExprKind::Unary(UnOp::Not, right_sub)) => { + let Some(left) = snippet_opt(cx, left_sub.span) else { + return; + }; + let Some(right) = snippet_opt(cx, right_sub.span) else { + return; + }; + let Some(op) = bin_op_eq_str(op) else { return }; + format!("{left} {op} {right}") + }, + (ExprKind::Unary(UnOp::Not, left_sub), _) => { + let Some(left) = snippet_opt(cx, left_sub.span) else { + return; + }; + let Some(right) = snippet_opt(cx, right.span) else { + return; + }; + let Some(op) = inverted_bin_op_eq_str(op) else { return }; + format!("{left} {op} {right}") + }, + (_, ExprKind::Unary(UnOp::Not, right_sub)) => { + let Some(left) = snippet_opt(cx, left.span) else { return }; + let Some(right) = snippet_opt(cx, right_sub.span) else { + return; + }; + let Some(op) = inverted_bin_op_eq_str(op) else { return }; + format!("{left} {op} {right}") + }, + _ => return, + }; + span_lint_and_sugg( + cx, + NONMINIMAL_BOOL, + expr_span, + "this boolean expression can be simplified", + "try", + suggestion, + Applicability::MachineApplicable, + ); } + struct NonminimalBoolVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, } diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs index ef12fe344e409..779ae03c4640b 100644 --- a/clippy_lints/src/box_default.rs +++ b/clippy_lints/src/box_default.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::macro_backtrace; +use clippy_utils::source::snippet_opt; use clippy_utils::ty::expr_sig; -use clippy_utils::{get_parent_node, is_default_equivalent, path_def_id}; +use clippy_utils::{is_default_equivalent, path_def_id}; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_ty, Visitor}; -use rustc_hir::{Block, Expr, ExprKind, Local, Node, QPath, TyKind}; +use rustc_hir::{Block, Expr, ExprKind, Local, Node, QPath, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::print::with_forced_trimmed_paths; @@ -41,13 +42,24 @@ declare_lint_pass!(BoxDefault => [BOX_DEFAULT]); impl LateLintPass<'_> for BoxDefault { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + // If the expression is a call (`Box::new(...)`) if let ExprKind::Call(box_new, [arg]) = expr.kind + // And call is of the form `::something` + // Here, it would be `::new` && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_new.kind - && let ExprKind::Call(arg_path, ..) = arg.kind - && !in_external_macro(cx.sess(), expr.span) - && (expr.span.eq_ctxt(arg.span) || is_local_vec_expn(cx, arg, expr)) + // And that method is `new` && seg.ident.name == sym::new + // And the call is that of a `Box` method && path_def_id(cx, ty).map_or(false, |id| Some(id) == cx.tcx.lang_items().owned_box()) + // And the single argument to the call is another function call + // This is the `T::default()` of `Box::new(T::default())` + && let ExprKind::Call(arg_path, inner_call_args) = arg.kind + // And we are not in a foreign crate's macro + && !in_external_macro(cx.sess(), expr.span) + // And the argument expression has the same context as the outer call expression + // or that we are inside a `vec!` macro expansion + && (expr.span.eq_ctxt(arg.span) || is_local_vec_expn(cx, arg, expr)) + // And the argument is equivalent to `Default::default()` && is_default_equivalent(cx, arg) { span_lint_and_sugg( @@ -59,7 +71,17 @@ impl LateLintPass<'_> for BoxDefault { if is_plain_default(cx, arg_path) || given_type(cx, expr) { "Box::default()".into() } else if let Some(arg_ty) = cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true) { - with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()")) + // Check if we can copy from the source expression in the replacement. + // We need the call to have no argument (see `explicit_default_type`). + if inner_call_args.is_empty() + && let Some(ty) = explicit_default_type(arg_path) + && let Some(s) = snippet_opt(cx, ty.span) + { + format!("Box::<{s}>::default()") + } else { + // Otherwise, use the inferred type's formatting. + with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()")) + } } else { return; }, @@ -81,6 +103,20 @@ fn is_plain_default(cx: &LateContext<'_>, arg_path: &Expr<'_>) -> bool { } } +// Checks whether the call is of the form `A::B::f()`. Returns `A::B` if it is. +// +// In the event we have this kind of construct, it's easy to use `A::B` as a replacement in the +// quickfix. `f` must however have no parameter. Should `f` have some, then some of the type of +// `A::B` may be inferred from the arguments. This would be the case for `Vec::from([0; false])`, +// where the argument to `from` allows inferring this is a `Vec` +fn explicit_default_type<'a>(arg_path: &'a Expr<'_>) -> Option<&'a Ty<'a>> { + if let ExprKind::Path(QPath::TypeRelative(ty, _)) = &arg_path.kind { + Some(ty) + } else { + None + } +} + fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>) -> bool { macro_backtrace(expr.span).next().map_or(false, |call| { cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id) && call.span.eq_ctxt(ref_expr.span) @@ -100,26 +136,23 @@ impl<'tcx> Visitor<'tcx> for InferVisitor { } fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - match get_parent_node(cx.tcx, expr.hir_id) { - Some(Node::Local(Local { ty: Some(ty), .. })) => { + match cx.tcx.parent_hir_node(expr.hir_id) { + Node::Local(Local { ty: Some(ty), .. }) => { let mut v = InferVisitor::default(); v.visit_ty(ty); !v.0 }, - Some( - Node::Expr(Expr { + Node::Expr(Expr { + kind: ExprKind::Call(path, args), + .. + }) + | Node::Block(Block { + expr: Some(Expr { kind: ExprKind::Call(path, args), .. - }) - | Node::Block(Block { - expr: - Some(Expr { - kind: ExprKind::Call(path, args), - .. - }), - .. }), - ) => { + .. + }) => { if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id) && let Some(sig) = expr_sig(cx, path) && let Some(input) = sig.input(index) diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 1543ae8039968..ab89bb2f5f159 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -131,8 +131,7 @@ pub(super) fn check( let cast_from_ptr_size = def.repr().int.map_or(true, |ty| matches!(ty, IntegerType::Pointer(_),)); let suffix = match (cast_from_ptr_size, is_isize_or_usize(cast_to)) { - (false, false) if from_nbits > to_nbits => "", - (true, false) if from_nbits > to_nbits => "", + (_, false) if from_nbits > to_nbits => "", (false, true) if from_nbits > 64 => "", (false, true) if from_nbits > 32 => " on targets with 32-bit wide pointers", _ => return, diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index 1df5a25f674d7..8fd95d9654cf0 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -1,15 +1,47 @@ +use std::convert::Infallible; +use std::ops::ControlFlow; + use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::{clip, method_chain_args, sext}; +use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::{method_chain_args, sext}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty, UintTy}; +use rustc_middle::ty::{self, Ty}; use super::CAST_SIGN_LOSS; -const METHODS_RET_POSITIVE: &[&str] = &["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"]; +/// A list of methods that can never return a negative value. +/// Includes methods that panic rather than returning a negative value. +/// +/// Methods that can overflow and return a negative value must not be included in this list, +/// because casting their return values can still result in sign loss. +const METHODS_RET_POSITIVE: &[&str] = &[ + "checked_abs", + "saturating_abs", + "isqrt", + "checked_isqrt", + "rem_euclid", + "checked_rem_euclid", + "wrapping_rem_euclid", +]; + +/// A list of methods that act like `pow()`. See `pow_call_result_sign()` for details. +/// +/// Methods that can overflow and return a negative value must not be included in this list, +/// because casting their return values can still result in sign loss. +const METHODS_POW: &[&str] = &["pow", "saturating_pow", "checked_pow"]; -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { +/// A list of methods that act like `unwrap()`, and don't change the sign of the inner value. +const METHODS_UNWRAP: &[&str] = &["unwrap", "unwrap_unchecked", "expect", "into_ok"]; + +pub(super) fn check<'cx>( + cx: &LateContext<'cx>, + expr: &Expr<'_>, + cast_op: &Expr<'_>, + cast_from: Ty<'cx>, + cast_to: Ty<'_>, +) { if should_lint(cx, cast_op, cast_from, cast_to) { span_lint( cx, @@ -20,35 +52,27 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_op: &Expr<'_>, c } } -fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) -> bool { +fn should_lint<'cx>(cx: &LateContext<'cx>, cast_op: &Expr<'_>, cast_from: Ty<'cx>, cast_to: Ty<'_>) -> bool { match (cast_from.is_integral(), cast_to.is_integral()) { (true, true) => { if !cast_from.is_signed() || cast_to.is_signed() { return false; } - // Don't lint if `cast_op` is known to be positive. + // Don't lint if `cast_op` is known to be positive, ignoring overflow. if let Sign::ZeroOrPositive = expr_sign(cx, cast_op, cast_from) { return false; } - let (mut uncertain_count, mut negative_count) = (0, 0); - // Peel off possible binary expressions, e.g. x * x * y => [x, x, y] - let Some(exprs) = exprs_with_selected_binop_peeled(cast_op) else { - // Assume cast sign lose if we cannot determine the sign of `cast_op` - return true; - }; - for expr in exprs { - let ty = cx.typeck_results().expr_ty(expr); - match expr_sign(cx, expr, ty) { - Sign::Negative => negative_count += 1, - Sign::Uncertain => uncertain_count += 1, - Sign::ZeroOrPositive => (), - }; + if let Sign::ZeroOrPositive = expr_muldiv_sign(cx, cast_op) { + return false; + } + + if let Sign::ZeroOrPositive = expr_add_sign(cx, cast_op) { + return false; } - // Lint if there are odd number of uncertain or negative results - uncertain_count % 2 == 1 || negative_count % 2 == 1 + true }, (false, true) => !cast_to.is_signed(), @@ -57,7 +81,13 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast } } -fn get_const_int_eval(cx: &LateContext<'_>, expr: &Expr<'_>, ty: Ty<'_>) -> Option { +fn get_const_signed_int_eval<'cx>( + cx: &LateContext<'cx>, + expr: &Expr<'_>, + ty: impl Into>>, +) -> Option { + let ty = ty.into().unwrap_or_else(|| cx.typeck_results().expr_ty(expr)); + if let Constant::Int(n) = constant(cx, cx.typeck_results(), expr)? && let ty::Int(ity) = *ty.kind() { @@ -66,29 +96,52 @@ fn get_const_int_eval(cx: &LateContext<'_>, expr: &Expr<'_>, ty: Ty<'_>) -> Opti None } +fn get_const_unsigned_int_eval<'cx>( + cx: &LateContext<'cx>, + expr: &Expr<'_>, + ty: impl Into>>, +) -> Option { + let ty = ty.into().unwrap_or_else(|| cx.typeck_results().expr_ty(expr)); + + if let Constant::Int(n) = constant(cx, cx.typeck_results(), expr)? + && let ty::Uint(_ity) = *ty.kind() + { + return Some(n); + } + None +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] enum Sign { ZeroOrPositive, Negative, Uncertain, } -fn expr_sign(cx: &LateContext<'_>, expr: &Expr<'_>, ty: Ty<'_>) -> Sign { +fn expr_sign<'cx>(cx: &LateContext<'cx>, expr: &Expr<'_>, ty: impl Into>>) -> Sign { // Try evaluate this expr first to see if it's positive - if let Some(val) = get_const_int_eval(cx, expr, ty) { + if let Some(val) = get_const_signed_int_eval(cx, expr, ty) { return if val >= 0 { Sign::ZeroOrPositive } else { Sign::Negative }; } + if let Some(_val) = get_const_unsigned_int_eval(cx, expr, None) { + return Sign::ZeroOrPositive; + } + // Calling on methods that always return non-negative values. if let ExprKind::MethodCall(path, caller, args, ..) = expr.kind { let mut method_name = path.ident.name.as_str(); - if method_name == "unwrap" - && let Some(arglist) = method_chain_args(expr, &["unwrap"]) + // Peel unwrap(), expect(), etc. + while let Some(&found_name) = METHODS_UNWRAP.iter().find(|&name| &method_name == name) + && let Some(arglist) = method_chain_args(expr, &[found_name]) && let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind { + // The original type has changed, but we can't use `ty` here anyway, because it has been + // moved. method_name = inner_path.ident.name.as_str(); } - if method_name == "pow" + if METHODS_POW.iter().any(|&name| method_name == name) && let [arg] = args { return pow_call_result_sign(cx, caller, arg); @@ -100,53 +153,182 @@ fn expr_sign(cx: &LateContext<'_>, expr: &Expr<'_>, ty: Ty<'_>) -> Sign { Sign::Uncertain } -/// Return the sign of the `pow` call's result. +/// Return the sign of the `pow` call's result, ignoring overflow. /// -/// If the caller is a positive number, the result is always positive, -/// If the `power_of` is a even number, the result is always positive as well, -/// Otherwise a [`Sign::Uncertain`] will be returned. -fn pow_call_result_sign(cx: &LateContext<'_>, caller: &Expr<'_>, power_of: &Expr<'_>) -> Sign { - let caller_ty = cx.typeck_results().expr_ty(caller); - if let Some(caller_val) = get_const_int_eval(cx, caller, caller_ty) - && caller_val >= 0 - { - return Sign::ZeroOrPositive; +/// If the base is positive, the result is always positive. +/// If the exponent is a even number, the result is always positive, +/// Otherwise, if the base is negative, and the exponent is an odd number, the result is always +/// negative. +/// +/// Otherwise, returns [`Sign::Uncertain`]. +fn pow_call_result_sign(cx: &LateContext<'_>, base: &Expr<'_>, exponent: &Expr<'_>) -> Sign { + let base_sign = expr_sign(cx, base, None); + + // Rust's integer pow() functions take an unsigned exponent. + let exponent_val = get_const_unsigned_int_eval(cx, exponent, None); + let exponent_is_even = exponent_val.map(|val| val % 2 == 0); + + match (base_sign, exponent_is_even) { + // Non-negative bases always return non-negative results, ignoring overflow. + (Sign::ZeroOrPositive, _) | + // Any base raised to an even exponent is non-negative. + // These both hold even if we don't know the value of the base. + (_, Some(true)) + => Sign::ZeroOrPositive, + + // A negative base raised to an odd exponent is non-negative. + (Sign::Negative, Some(false)) => Sign::Negative, + + // Negative/unknown base to an unknown exponent, or unknown base to an odd exponent. + // Could be negative or positive depending on the actual values. + (Sign::Negative | Sign::Uncertain, None) | + (Sign::Uncertain, Some(false)) => Sign::Uncertain, } +} - if let Some(Constant::Int(n)) = constant(cx, cx.typeck_results(), power_of) - && clip(cx.tcx, n, UintTy::U32) % 2 == 0 - { - return Sign::ZeroOrPositive; +/// Peels binary operators such as [`BinOpKind::Mul`] or [`BinOpKind::Rem`], +/// where the result could always be positive. See [`exprs_with_muldiv_binop_peeled()`] for details. +/// +/// Returns the sign of the list of peeled expressions. +fn expr_muldiv_sign(cx: &LateContext<'_>, expr: &Expr<'_>) -> Sign { + let mut negative_count = 0; + + // Peel off possible binary expressions, for example: + // x * x / y => [x, x, y] + // a % b => [a] + let exprs = exprs_with_muldiv_binop_peeled(expr); + for expr in exprs { + match expr_sign(cx, expr, None) { + Sign::Negative => negative_count += 1, + // A mul/div is: + // - uncertain if there are any uncertain values (because they could be negative or positive), + Sign::Uncertain => return Sign::Uncertain, + Sign::ZeroOrPositive => (), + }; } - Sign::Uncertain + // A mul/div is: + // - negative if there are an odd number of negative values, + // - positive or zero otherwise. + if negative_count % 2 == 1 { + Sign::Negative + } else { + Sign::ZeroOrPositive + } +} + +/// Peels binary operators such as [`BinOpKind::Add`], where the result could always be positive. +/// See [`exprs_with_add_binop_peeled()`] for details. +/// +/// Returns the sign of the list of peeled expressions. +fn expr_add_sign(cx: &LateContext<'_>, expr: &Expr<'_>) -> Sign { + let mut negative_count = 0; + let mut positive_count = 0; + + // Peel off possible binary expressions, for example: + // a + b + c => [a, b, c] + let exprs = exprs_with_add_binop_peeled(expr); + for expr in exprs { + match expr_sign(cx, expr, None) { + Sign::Negative => negative_count += 1, + // A sum is: + // - uncertain if there are any uncertain values (because they could be negative or positive), + Sign::Uncertain => return Sign::Uncertain, + Sign::ZeroOrPositive => positive_count += 1, + }; + } + + // A sum is: + // - positive or zero if there are only positive (or zero) values, + // - negative if there are only negative (or zero) values, or + // - uncertain if there are both. + // We could split Zero out into its own variant, but we don't yet. + if negative_count == 0 { + Sign::ZeroOrPositive + } else if positive_count == 0 { + Sign::Negative + } else { + Sign::Uncertain + } } /// Peels binary operators such as [`BinOpKind::Mul`], [`BinOpKind::Div`] or [`BinOpKind::Rem`], -/// which the result could always be positive under certain condition. +/// where the result depends on: +/// - the number of negative values in the entire expression, or +/// - the number of negative values on the left hand side of the expression. +/// Ignores overflow. /// -/// Other operators such as `+`/`-` causing the result's sign hard to determine, which we will -/// return `None` -fn exprs_with_selected_binop_peeled<'a>(expr: &'a Expr<'_>) -> Option>> { - #[inline] - fn collect_operands<'a>(expr: &'a Expr<'a>, operands: &mut Vec<&'a Expr<'a>>) -> Option<()> { - match expr.kind { - ExprKind::Binary(op, lhs, rhs) => { - if matches!(op.node, BinOpKind::Mul | BinOpKind::Div | BinOpKind::Rem) { - collect_operands(lhs, operands); - operands.push(rhs); - } else { - // Things are complicated when there are other binary ops exist, - // abort checking by returning `None` for now. - return None; - } - }, - _ => operands.push(expr), +/// +/// Expressions using other operators are preserved, so we can try to evaluate them later. +fn exprs_with_muldiv_binop_peeled<'e>(expr: &'e Expr<'_>) -> Vec<&'e Expr<'e>> { + let mut res = vec![]; + + for_each_expr(expr, |sub_expr| -> ControlFlow { + // We don't check for mul/div/rem methods here, but we could. + if let ExprKind::Binary(op, lhs, _rhs) = sub_expr.kind { + if matches!(op.node, BinOpKind::Mul | BinOpKind::Div) { + // For binary operators where both sides contribute to the sign of the result, + // collect all their operands, recursively. This ignores overflow. + ControlFlow::Continue(Descend::Yes) + } else if matches!(op.node, BinOpKind::Rem | BinOpKind::Shr) { + // For binary operators where the left hand side determines the sign of the result, + // only collect that side, recursively. Overflow panics, so this always holds. + // + // Large left shifts turn negatives into zeroes, so we can't use it here. + // + // > Given remainder = dividend % divisor, the remainder will have the same sign as the dividend + // > ... + // > Arithmetic right shift on signed integer types + // https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators + + // We want to descend into the lhs, but skip the rhs. + // That's tricky to do using for_each_expr(), so we just keep the lhs intact. + res.push(lhs); + ControlFlow::Continue(Descend::No) + } else { + // The sign of the result of other binary operators depends on the values of the operands, + // so try to evaluate the expression. + res.push(sub_expr); + ControlFlow::Continue(Descend::No) + } + } else { + // For other expressions, including unary operators and constants, try to evaluate the expression. + res.push(sub_expr); + ControlFlow::Continue(Descend::No) } - Some(()) - } + }); + res +} + +/// Peels binary operators such as [`BinOpKind::Add`], where the result depends on: +/// - all the expressions being positive, or +/// - all the expressions being negative. +/// Ignores overflow. +/// +/// Expressions using other operators are preserved, so we can try to evaluate them later. +fn exprs_with_add_binop_peeled<'e>(expr: &'e Expr<'_>) -> Vec<&'e Expr<'e>> { let mut res = vec![]; - collect_operands(expr, &mut res)?; - Some(res) + + for_each_expr(expr, |sub_expr| -> ControlFlow { + // We don't check for add methods here, but we could. + if let ExprKind::Binary(op, _lhs, _rhs) = sub_expr.kind { + if matches!(op.node, BinOpKind::Add) { + // For binary operators where both sides contribute to the sign of the result, + // collect all their operands, recursively. This ignores overflow. + ControlFlow::Continue(Descend::Yes) + } else { + // The sign of the result of other binary operators depends on the values of the operands, + // so try to evaluate the expression. + res.push(sub_expr); + ControlFlow::Continue(Descend::No) + } + } else { + // For other expressions, including unary operators and constants, try to evaluate the expression. + res.push(sub_expr); + ControlFlow::Continue(Descend::No) + } + }); + + res } diff --git a/clippy_lints/src/casts/ref_as_ptr.rs b/clippy_lints/src/casts/ref_as_ptr.rs index d600d2aec1b5e..9d5a486336d5f 100644 --- a/clippy_lints/src/casts/ref_as_ptr.rs +++ b/clippy_lints/src/casts/ref_as_ptr.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_no_std_crate; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; +use clippy_utils::{expr_use_ctxt, is_no_std_crate, ExprUseNode}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability, Ty, TyKind}; use rustc_lint::LateContext; @@ -9,7 +9,12 @@ use rustc_middle::ty::{self, TypeAndMut}; use super::REF_AS_PTR; -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to_hir_ty: &Ty<'_>) { +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + cast_expr: &'tcx Expr<'_>, + cast_to_hir_ty: &Ty<'_>, +) { let (cast_from, cast_to) = ( cx.typeck_results().expr_ty(cast_expr), cx.typeck_results().expr_ty(expr), @@ -17,6 +22,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, if matches!(cast_from.kind(), ty::Ref(..)) && let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, .. }) = cast_to.kind() + && let Some(use_cx) = expr_use_ctxt(cx, expr) + // TODO: only block the lint if `cast_expr` is a temporary + && !matches!(use_cx.node, ExprUseNode::Local(_) | ExprUseNode::ConstStatic(_)) { let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" }; let fn_name = match to_mutbl { diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index b4a23d0d4db41..cc513d46bf4ec 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::numeric_literal::NumericLiteral; use clippy_utils::source::snippet_opt; use clippy_utils::visitors::{for_each_expr, Visitable}; -use clippy_utils::{get_parent_expr, get_parent_node, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local}; +use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local}; use rustc_ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -264,8 +264,7 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx } // Local usage } else if let Res::Local(hir_id) = res - && let Some(parent) = get_parent_node(cx.tcx, hir_id) - && let Node::Local(l) = parent + && let Node::Local(l) = cx.tcx.parent_hir_node(hir_id) { if let Some(e) = l.init && is_cast_from_ty_alias(cx, e, cast_from) diff --git a/clippy_lints/src/collection_is_never_read.rs b/clippy_lints/src/collection_is_never_read.rs index d0c989cfff304..d820413e11129 100644 --- a/clippy_lints/src/collection_is_never_read.rs +++ b/clippy_lints/src/collection_is_never_read.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::visitors::for_each_expr_with_closures; -use clippy_utils::{get_enclosing_block, get_parent_node, path_to_local_id}; +use clippy_utils::{get_enclosing_block, path_to_local_id}; use core::ops::ControlFlow; use rustc_hir::{Block, ExprKind, HirId, LangItem, Local, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -94,7 +94,7 @@ fn has_no_read_access<'tcx>(cx: &LateContext<'tcx>, id: HirId, block: &'tcx Bloc // `id` appearing in the left-hand side of an assignment is not a read access: // // id = ...; // Not reading `id`. - if let Some(Node::Expr(parent)) = get_parent_node(cx.tcx, expr.hir_id) + if let Node::Expr(parent) = cx.tcx.parent_hir_node(expr.hir_id) && let ExprKind::Assign(lhs, ..) = parent.kind && path_to_local_id(lhs, id) { @@ -108,7 +108,7 @@ fn has_no_read_access<'tcx>(cx: &LateContext<'tcx>, id: HirId, block: &'tcx Bloc // Only assuming this for "official" methods defined on the type. For methods defined in extension // traits (identified as local, based on the orphan rule), pessimistically assume that they might // have side effects, so consider them a read. - if let Some(Node::Expr(parent)) = get_parent_node(cx.tcx, expr.hir_id) + if let Node::Expr(parent) = cx.tcx.parent_hir_node(expr.hir_id) && let ExprKind::MethodCall(_, receiver, _, _) = parent.kind && path_to_local_id(receiver, id) && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id) @@ -117,7 +117,7 @@ fn has_no_read_access<'tcx>(cx: &LateContext<'tcx>, id: HirId, block: &'tcx Bloc // The method call is a statement, so the return value is not used. That's not a read access: // // id.foo(args); - if let Some(Node::Stmt(..)) = get_parent_node(cx.tcx, parent.hir_id) { + if let Node::Stmt(..) = cx.tcx.parent_hir_node(parent.hir_id) { return ControlFlow::Continue(()); } diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 0a5baabd973ea..fb3ae2457e3c4 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -51,6 +51,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON_INFO, crate::attrs::BLANKET_CLIPPY_RESTRICTION_LINTS_INFO, crate::attrs::DEPRECATED_CFG_ATTR_INFO, + crate::attrs::DEPRECATED_CLIPPY_CFG_ATTR_INFO, crate::attrs::DEPRECATED_SEMVER_INFO, crate::attrs::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO, crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO, @@ -59,6 +60,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::attrs::MISMATCHED_TARGET_OS_INFO, crate::attrs::NON_MINIMAL_CFG_INFO, crate::attrs::SHOULD_PANIC_WITHOUT_EXPECT_INFO, + crate::attrs::UNNECESSARY_CLIPPY_CFG_INFO, crate::attrs::USELESS_ATTRIBUTE_INFO, crate::await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE_INFO, crate::await_holding_invalid::AWAIT_HOLDING_LOCK_INFO, @@ -137,6 +139,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::disallowed_types::DISALLOWED_TYPES_INFO, crate::doc::DOC_LINK_WITH_QUOTES_INFO, crate::doc::DOC_MARKDOWN_INFO, + crate::doc::EMPTY_DOCS_INFO, crate::doc::MISSING_ERRORS_DOC_INFO, crate::doc::MISSING_PANICS_DOC_INFO, crate::doc::MISSING_SAFETY_DOC_INFO, @@ -453,6 +456,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::UNNECESSARY_FILTER_MAP_INFO, crate::methods::UNNECESSARY_FIND_MAP_INFO, crate::methods::UNNECESSARY_FOLD_INFO, + crate::methods::UNNECESSARY_GET_THEN_CHECK_INFO, crate::methods::UNNECESSARY_JOIN_INFO, crate::methods::UNNECESSARY_LAZY_EVALUATIONS_INFO, crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO, @@ -497,6 +501,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::module_style::MOD_MODULE_FILES_INFO, crate::module_style::SELF_NAMED_MODULE_FILES_INFO, crate::multi_assignments::MULTI_ASSIGNMENTS_INFO, + crate::multiple_bound_locations::MULTIPLE_BOUND_LOCATIONS_INFO, crate::multiple_unsafe_ops_per_block::MULTIPLE_UNSAFE_OPS_PER_BLOCK_INFO, crate::mut_key::MUTABLE_KEY_TYPE_INFO, crate::mut_mut::MUT_MUT_INFO, diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 0ddfeaa0ae059..560b2acc1c702 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -2,9 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::ty::{implements_trait, is_manually_drop, peel_mid_ty_refs}; -use clippy_utils::{ - expr_use_ctxt, get_parent_expr, get_parent_node, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode, -}; +use clippy_utils::{expr_use_ctxt, get_parent_expr, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode}; use core::mem; use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; use rustc_data_structures::fx::FxIndexMap; @@ -1008,8 +1006,8 @@ fn report<'tcx>( data.first_expr.span, state.msg, |diag| { - let (precedence, calls_field) = match get_parent_node(cx.tcx, data.first_expr.hir_id) { - Some(Node::Expr(e)) => match e.kind { + let (precedence, calls_field) = match cx.tcx.parent_hir_node(data.first_expr.hir_id) { + Node::Expr(e) => match e.kind { ExprKind::Call(callee, _) if callee.hir_id != data.first_expr.hir_id => (0, false), ExprKind::Call(..) => (PREC_POSTFIX, matches!(expr.kind, ExprKind::Field(..))), _ => (e.precedence().order(), false), diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs index 656b3d9bfaf1b..75379cb4e5458 100644 --- a/clippy_lints/src/disallowed_macros.rs +++ b/clippy_lints/src/disallowed_macros.rs @@ -1,13 +1,16 @@ use clippy_config::types::DisallowedPath; -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::macros::macro_backtrace; use rustc_ast::Attribute; use rustc_data_structures::fx::FxHashSet; +use rustc_errors::DiagnosticBuilder; use rustc_hir::def_id::DefIdMap; -use rustc_hir::{Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, Pat, Path, Stmt, TraitItem, Ty}; +use rustc_hir::{ + Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty, +}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::{ExpnId, Span}; +use rustc_span::{ExpnId, MacroKind, Span}; declare_clippy_lint! { /// ### What it does @@ -57,6 +60,10 @@ pub struct DisallowedMacros { conf_disallowed: Vec, disallowed: DefIdMap, seen: FxHashSet, + + // Track the most recently seen node that can have a `derive` attribute. + // Needed to use the correct lint level. + derive_src: Option, } impl DisallowedMacros { @@ -65,10 +72,11 @@ impl DisallowedMacros { conf_disallowed, disallowed: DefIdMap::default(), seen: FxHashSet::default(), + derive_src: None, } } - fn check(&mut self, cx: &LateContext<'_>, span: Span) { + fn check(&mut self, cx: &LateContext<'_>, span: Span, derive_src: Option) { if self.conf_disallowed.is_empty() { return; } @@ -80,18 +88,26 @@ impl DisallowedMacros { if let Some(&index) = self.disallowed.get(&mac.def_id) { let conf = &self.conf_disallowed[index]; - - span_lint_and_then( - cx, - DISALLOWED_MACROS, - mac.span, - &format!("use of a disallowed macro `{}`", conf.path()), - |diag| { - if let Some(reason) = conf.reason() { - diag.note(reason); - } - }, - ); + let msg = format!("use of a disallowed macro `{}`", conf.path()); + let add_note = |diag: &mut DiagnosticBuilder<'_, _>| { + if let Some(reason) = conf.reason() { + diag.note(reason); + } + }; + if matches!(mac.kind, MacroKind::Derive) + && let Some(derive_src) = derive_src + { + span_lint_hir_and_then( + cx, + DISALLOWED_MACROS, + cx.tcx.local_def_id_to_hir_id(derive_src.def_id), + mac.span, + &msg, + add_note, + ); + } else { + span_lint_and_then(cx, DISALLOWED_MACROS, mac.span, &msg, add_note); + } } } } @@ -110,49 +126,57 @@ impl LateLintPass<'_> for DisallowedMacros { } fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - self.check(cx, expr.span); + self.check(cx, expr.span, None); // `$t + $t` can have the context of $t, check also the span of the binary operator if let ExprKind::Binary(op, ..) = expr.kind { - self.check(cx, op.span); + self.check(cx, op.span, None); } } fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) { - self.check(cx, stmt.span); + self.check(cx, stmt.span, None); } fn check_ty(&mut self, cx: &LateContext<'_>, ty: &Ty<'_>) { - self.check(cx, ty.span); + self.check(cx, ty.span, None); } fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) { - self.check(cx, pat.span); + self.check(cx, pat.span, None); } fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - self.check(cx, item.span); - self.check(cx, item.vis_span); + self.check(cx, item.span, self.derive_src); + self.check(cx, item.vis_span, None); + + if matches!( + item.kind, + ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..) + ) && macro_backtrace(item.span).all(|m| !matches!(m.kind, MacroKind::Derive)) + { + self.derive_src = Some(item.owner_id); + } } fn check_foreign_item(&mut self, cx: &LateContext<'_>, item: &ForeignItem<'_>) { - self.check(cx, item.span); - self.check(cx, item.vis_span); + self.check(cx, item.span, None); + self.check(cx, item.vis_span, None); } fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &ImplItem<'_>) { - self.check(cx, item.span); - self.check(cx, item.vis_span); + self.check(cx, item.span, None); + self.check(cx, item.vis_span, None); } fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) { - self.check(cx, item.span); + self.check(cx, item.span, None); } fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, _: HirId) { - self.check(cx, path.span); + self.check(cx, path.span, None); } fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &Attribute) { - self.check(cx, attr.span); + self.check(cx, attr.span, self.derive_src); } } diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs index 2b4ce6ddfaaa3..9af34c3a7bf0b 100644 --- a/clippy_lints/src/doc/mod.rs +++ b/clippy_lints/src/doc/mod.rs @@ -19,7 +19,8 @@ use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_resolve::rustdoc::{ - add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, DocFragment, + add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, span_of_fragments, + DocFragment, }; use rustc_session::impl_lint_pass; use rustc_span::edition::Edition; @@ -338,6 +339,30 @@ declare_clippy_lint! { "suspicious usage of (outer) doc comments" } +declare_clippy_lint! { + /// ### What it does + /// Detects documentation that is empty. + /// ### Why is this bad? + /// Empty docs clutter code without adding value, reducing readability and maintainability. + /// ### Example + /// ```no_run + /// /// + /// fn returns_true() -> bool { + /// true + /// } + /// ``` + /// Use instead: + /// ```no_run + /// fn returns_true() -> bool { + /// true + /// } + /// ``` + #[clippy::version = "1.78.0"] + pub EMPTY_DOCS, + suspicious, + "docstrings exist but documentation is empty" +} + #[derive(Clone)] pub struct Documentation { valid_idents: FxHashSet, @@ -364,7 +389,8 @@ impl_lint_pass!(Documentation => [ NEEDLESS_DOCTEST_MAIN, TEST_ATTR_IN_DOCTEST, UNNECESSARY_SAFETY_DOC, - SUSPICIOUS_DOC_COMMENTS + SUSPICIOUS_DOC_COMMENTS, + EMPTY_DOCS, ]); impl<'tcx> LateLintPass<'tcx> for Documentation { @@ -373,11 +399,22 @@ impl<'tcx> LateLintPass<'tcx> for Documentation { check_attrs(cx, &self.valid_idents, attrs); } + fn check_variant(&mut self, cx: &LateContext<'tcx>, variant: &'tcx hir::Variant<'tcx>) { + let attrs = cx.tcx.hir().attrs(variant.hir_id); + check_attrs(cx, &self.valid_idents, attrs); + } + + fn check_field_def(&mut self, cx: &LateContext<'tcx>, variant: &'tcx hir::FieldDef<'tcx>) { + let attrs = cx.tcx.hir().attrs(variant.hir_id); + check_attrs(cx, &self.valid_idents, attrs); + } + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { let attrs = cx.tcx.hir().attrs(item.hir_id()); let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { return; }; + match item.kind { hir::ItemKind::Fn(ref sig, _, body_id) => { if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) { @@ -502,13 +539,23 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ suspicious_doc_comments::check(cx, attrs); let (fragments, _) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), true); - let mut doc = String::new(); - for fragment in &fragments { - add_doc_fragment(&mut doc, fragment); - } + let mut doc = fragments.iter().fold(String::new(), |mut acc, fragment| { + add_doc_fragment(&mut acc, fragment); + acc + }); doc.pop(); - if doc.is_empty() { + if doc.trim().is_empty() { + if let Some(span) = span_of_fragments(&fragments) { + span_lint_and_help( + cx, + EMPTY_DOCS, + span, + "empty doc comment", + None, + "consider removing or filling it", + ); + } return Some(DocHeaders::default()); } diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 124d78fc4ffdc..bf6f54c1e72a3 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::is_must_use_func_call; use clippy_utils::ty::{is_copy, is_must_use_ty, is_type_lang_item}; -use clippy_utils::{get_parent_node, is_must_use_func_call}; use rustc_hir::{Arm, Expr, ExprKind, LangItem, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -144,8 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { // } fn is_single_call_in_arm<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'_>, drop_expr: &'tcx Expr<'_>) -> bool { if matches!(arg.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)) { - let parent_node = get_parent_node(cx.tcx, drop_expr.hir_id); - if let Some(Node::Arm(Arm { body, .. })) = &parent_node { + if let Node::Arm(Arm { body, .. }) = cx.tcx.parent_hir_node(drop_expr.hir_id) { return body.hir_id == drop_expr.hir_id; } } diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 8af321e4d553b..61f550ce0beb4 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diag_trait_item; use clippy_utils::macros::{ find_format_arg_expr, find_format_args, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, - is_format_macro, is_panic, root_macro_call, root_macro_call_first_node, FormatParamUsage, + is_format_macro, is_panic, root_macro_call, root_macro_call_first_node, FormatParamUsage, MacroCall, }; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_lang_item}; @@ -20,7 +20,6 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; -use rustc_span::def_id::DefId; use rustc_span::edition::Edition::Edition2021; use rustc_span::{sym, Span, Symbol}; @@ -189,32 +188,18 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs { && is_format_macro(cx, macro_call.def_id) && let Some(format_args) = find_format_args(cx, expr, macro_call.expn) { - for piece in &format_args.template { - if let FormatArgsPiece::Placeholder(placeholder) = piece - && let Ok(index) = placeholder.argument.index - && let Some(arg) = format_args.arguments.all_args().get(index) - { - let arg_expr = find_format_arg_expr(expr, arg); - - check_unused_format_specifier(cx, placeholder, arg_expr); - - if placeholder.format_trait != FormatTrait::Display - || placeholder.format_options != FormatOptions::default() - || is_aliased(&format_args, index) - { - continue; - } + let linter = FormatArgsExpr { + cx, + expr, + macro_call: ¯o_call, + format_args: &format_args, + ignore_mixed: self.ignore_mixed, + }; - if let Ok(arg_hir_expr) = arg_expr { - let name = cx.tcx.item_name(macro_call.def_id); - check_format_in_format_args(cx, macro_call.span, name, arg_hir_expr); - check_to_string_in_format_args(cx, name, arg_hir_expr); - } - } - } + linter.check_templates(); if self.msrv.meets(msrvs::FORMAT_ARGS_CAPTURE) { - check_uninlined_args(cx, &format_args, macro_call.span, macro_call.def_id, self.ignore_mixed); + linter.check_uninlined_args(); } } } @@ -222,255 +207,279 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs { extract_msrv_attr!(LateContext); } -fn check_unused_format_specifier( - cx: &LateContext<'_>, - placeholder: &FormatPlaceholder, - arg_expr: Result<&Expr<'_>, &rustc_ast::Expr>, -) { - let ty_or_ast_expr = arg_expr.map(|expr| cx.typeck_results().expr_ty(expr).peel_refs()); - - let is_format_args = match ty_or_ast_expr { - Ok(ty) => is_type_lang_item(cx, ty, LangItem::FormatArguments), - Err(expr) => matches!(expr.peel_parens_and_refs().kind, rustc_ast::ExprKind::FormatArgs(_)), - }; - - let options = &placeholder.format_options; - - let arg_span = match arg_expr { - Ok(expr) => expr.span, - Err(expr) => expr.span, - }; - - if let Some(placeholder_span) = placeholder.span - && is_format_args - && *options != FormatOptions::default() - { - span_lint_and_then( - cx, - UNUSED_FORMAT_SPECS, - placeholder_span, - "format specifiers have no effect on `format_args!()`", - |diag| { - let mut suggest_format = |spec| { - let message = format!("for the {spec} to apply consider using `format!()`"); - - if let Some(mac_call) = root_macro_call(arg_span) - && cx.tcx.is_diagnostic_item(sym::format_args_macro, mac_call.def_id) - { - diag.span_suggestion( - cx.sess().source_map().span_until_char(mac_call.span, '!'), - message, - "format", - Applicability::MaybeIncorrect, - ); - } else { - diag.help(message); - } - }; +struct FormatArgsExpr<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + macro_call: &'a MacroCall, + format_args: &'a rustc_ast::FormatArgs, + ignore_mixed: bool, +} - if options.width.is_some() { - suggest_format("width"); +impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> { + fn check_templates(&self) { + for piece in &self.format_args.template { + if let FormatArgsPiece::Placeholder(placeholder) = piece + && let Ok(index) = placeholder.argument.index + && let Some(arg) = self.format_args.arguments.all_args().get(index) + { + let arg_expr = find_format_arg_expr(self.expr, arg); + + self.check_unused_format_specifier(placeholder, arg_expr); + + if let Ok(arg_expr) = arg_expr + && placeholder.format_trait == FormatTrait::Display + && placeholder.format_options == FormatOptions::default() + && !self.is_aliased(index) + { + let name = self.cx.tcx.item_name(self.macro_call.def_id); + self.check_format_in_format_args(name, arg_expr); + self.check_to_string_in_format_args(name, arg_expr); } + } + } + } - if options.precision.is_some() { - suggest_format("precision"); - } + fn check_unused_format_specifier( + &self, + placeholder: &FormatPlaceholder, + arg_expr: Result<&Expr<'_>, &rustc_ast::Expr>, + ) { + let ty_or_ast_expr = arg_expr.map(|expr| self.cx.typeck_results().expr_ty(expr).peel_refs()); - if let Some(format_span) = format_placeholder_format_span(placeholder) { - diag.span_suggestion_verbose( - format_span, - "if the current behavior is intentional, remove the format specifiers", - "", - Applicability::MaybeIncorrect, - ); - } - }, - ); - } -} + let is_format_args = match ty_or_ast_expr { + Ok(ty) => is_type_lang_item(self.cx, ty, LangItem::FormatArguments), + Err(expr) => matches!(expr.peel_parens_and_refs().kind, rustc_ast::ExprKind::FormatArgs(_)), + }; -fn check_uninlined_args( - cx: &LateContext<'_>, - args: &rustc_ast::FormatArgs, - call_site: Span, - def_id: DefId, - ignore_mixed: bool, -) { - if args.span.from_expansion() { - return; - } - if call_site.edition() < Edition2021 && (is_panic(cx, def_id) || is_assert_macro(cx, def_id)) { - // panic!, assert!, and debug_assert! before 2021 edition considers a single string argument as - // non-format - return; + let options = &placeholder.format_options; + + let arg_span = match arg_expr { + Ok(expr) => expr.span, + Err(expr) => expr.span, + }; + + if let Some(placeholder_span) = placeholder.span + && is_format_args + && *options != FormatOptions::default() + { + span_lint_and_then( + self.cx, + UNUSED_FORMAT_SPECS, + placeholder_span, + "format specifiers have no effect on `format_args!()`", + |diag| { + let mut suggest_format = |spec| { + let message = format!("for the {spec} to apply consider using `format!()`"); + + if let Some(mac_call) = root_macro_call(arg_span) + && self.cx.tcx.is_diagnostic_item(sym::format_args_macro, mac_call.def_id) + { + diag.span_suggestion( + self.cx.sess().source_map().span_until_char(mac_call.span, '!'), + message, + "format", + Applicability::MaybeIncorrect, + ); + } else { + diag.help(message); + } + }; + + if options.width.is_some() { + suggest_format("width"); + } + + if options.precision.is_some() { + suggest_format("precision"); + } + + if let Some(format_span) = format_placeholder_format_span(placeholder) { + diag.span_suggestion_verbose( + format_span, + "if the current behavior is intentional, remove the format specifiers", + "", + Applicability::MaybeIncorrect, + ); + } + }, + ); + } } - let mut fixes = Vec::new(); - // If any of the arguments are referenced by an index number, - // and that argument is not a simple variable and cannot be inlined, - // we cannot remove any other arguments in the format string, - // because the index numbers might be wrong after inlining. - // Example of an un-inlinable format: print!("{}{1}", foo, 2) - for (pos, usage) in format_arg_positions(args) { - if !check_one_arg(args, pos, usage, &mut fixes, ignore_mixed) { + fn check_uninlined_args(&self) { + if self.format_args.span.from_expansion() { + return; + } + if self.macro_call.span.edition() < Edition2021 + && (is_panic(self.cx, self.macro_call.def_id) || is_assert_macro(self.cx, self.macro_call.def_id)) + { + // panic!, assert!, and debug_assert! before 2021 edition considers a single string argument as + // non-format return; } - } - if fixes.is_empty() { - return; - } + let mut fixes = Vec::new(); + // If any of the arguments are referenced by an index number, + // and that argument is not a simple variable and cannot be inlined, + // we cannot remove any other arguments in the format string, + // because the index numbers might be wrong after inlining. + // Example of an un-inlinable format: print!("{}{1}", foo, 2) + for (pos, usage) in self.format_arg_positions() { + if !self.check_one_arg(pos, usage, &mut fixes) { + return; + } + } - // multiline span display suggestion is sometimes broken: https://github.com/rust-lang/rust/pull/102729#discussion_r988704308 - // in those cases, make the code suggestion hidden - let multiline_fix = fixes.iter().any(|(span, _)| cx.sess().source_map().is_multiline(*span)); - - // Suggest removing each argument only once, for example in `format!("{0} {0}", arg)`. - fixes.sort_unstable_by_key(|(span, _)| *span); - fixes.dedup_by_key(|(span, _)| *span); - - span_lint_and_then( - cx, - UNINLINED_FORMAT_ARGS, - call_site, - "variables can be used directly in the `format!` string", - |diag| { - diag.multipart_suggestion_with_style( - "change this to", - fixes, - Applicability::MachineApplicable, - if multiline_fix { CompletelyHidden } else { ShowCode }, - ); - }, - ); -} + if fixes.is_empty() { + return; + } -fn check_one_arg( - args: &rustc_ast::FormatArgs, - pos: &FormatArgPosition, - usage: FormatParamUsage, - fixes: &mut Vec<(Span, String)>, - ignore_mixed: bool, -) -> bool { - let index = pos.index.unwrap(); - let arg = &args.arguments.all_args()[index]; - - if !matches!(arg.kind, FormatArgumentKind::Captured(_)) - && let rustc_ast::ExprKind::Path(None, path) = &arg.expr.kind - && let [segment] = path.segments.as_slice() - && segment.args.is_none() - && let Some(arg_span) = format_arg_removal_span(args, index) - && let Some(pos_span) = pos.span - { - let replacement = match usage { - FormatParamUsage::Argument => segment.ident.name.to_string(), - FormatParamUsage::Width => format!("{}$", segment.ident.name), - FormatParamUsage::Precision => format!(".{}$", segment.ident.name), - }; - fixes.push((pos_span, replacement)); - fixes.push((arg_span, String::new())); - true // successful inlining, continue checking - } else { - // Do not continue inlining (return false) in case - // * if we can't inline a numbered argument, e.g. `print!("{0} ...", foo.bar, ...)` - // * if allow_mixed_uninlined_format_args is false and this arg hasn't been inlined already - pos.kind != FormatArgPositionKind::Number - && (!ignore_mixed || matches!(arg.kind, FormatArgumentKind::Captured(_))) - } -} + // multiline span display suggestion is sometimes broken: https://github.com/rust-lang/rust/pull/102729#discussion_r988704308 + // in those cases, make the code suggestion hidden + let multiline_fix = fixes + .iter() + .any(|(span, _)| self.cx.sess().source_map().is_multiline(*span)); -fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &Expr<'_>) { - let expn_data = arg.span.ctxt().outer_expn_data(); - if expn_data.call_site.from_expansion() { - return; - } - let Some(mac_id) = expn_data.macro_def_id else { return }; - if !cx.tcx.is_diagnostic_item(sym::format_macro, mac_id) { - return; + // Suggest removing each argument only once, for example in `format!("{0} {0}", arg)`. + fixes.sort_unstable_by_key(|(span, _)| *span); + fixes.dedup_by_key(|(span, _)| *span); + + span_lint_and_then( + self.cx, + UNINLINED_FORMAT_ARGS, + self.macro_call.span, + "variables can be used directly in the `format!` string", + |diag| { + diag.multipart_suggestion_with_style( + "change this to", + fixes, + Applicability::MachineApplicable, + if multiline_fix { CompletelyHidden } else { ShowCode }, + ); + }, + ); } - span_lint_and_then( - cx, - FORMAT_IN_FORMAT_ARGS, - call_site, - &format!("`format!` in `{name}!` args"), - |diag| { - diag.help(format!( - "combine the `format!(..)` arguments with the outer `{name}!(..)` call" - )); - diag.help("or consider changing `format!` to `format_args!`"); - }, - ); -} -fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Expr<'_>) { - if !value.span.from_expansion() - && let ExprKind::MethodCall(_, receiver, [], to_string_span) = value.kind - && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id) - && is_diag_trait_item(cx, method_def_id, sym::ToString) - && let receiver_ty = cx.typeck_results().expr_ty(receiver) - && let Some(display_trait_id) = cx.tcx.get_diagnostic_item(sym::Display) - && let (n_needed_derefs, target) = - count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter()) - && implements_trait(cx, target, display_trait_id, &[]) - && let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait() - && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) - { - let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]); - if n_needed_derefs == 0 && !needs_ref { - span_lint_and_sugg( - cx, - TO_STRING_IN_FORMAT_ARGS, - to_string_span.with_lo(receiver.span.hi()), - &format!("`to_string` applied to a type that implements `Display` in `{name}!` args"), - "remove this", - String::new(), - Applicability::MachineApplicable, - ); + fn check_one_arg(&self, pos: &FormatArgPosition, usage: FormatParamUsage, fixes: &mut Vec<(Span, String)>) -> bool { + let index = pos.index.unwrap(); + let arg = &self.format_args.arguments.all_args()[index]; + + if !matches!(arg.kind, FormatArgumentKind::Captured(_)) + && let rustc_ast::ExprKind::Path(None, path) = &arg.expr.kind + && let [segment] = path.segments.as_slice() + && segment.args.is_none() + && let Some(arg_span) = format_arg_removal_span(self.format_args, index) + && let Some(pos_span) = pos.span + { + let replacement = match usage { + FormatParamUsage::Argument => segment.ident.name.to_string(), + FormatParamUsage::Width => format!("{}$", segment.ident.name), + FormatParamUsage::Precision => format!(".{}$", segment.ident.name), + }; + fixes.push((pos_span, replacement)); + fixes.push((arg_span, String::new())); + true // successful inlining, continue checking } else { - span_lint_and_sugg( - cx, - TO_STRING_IN_FORMAT_ARGS, - value.span, - &format!("`to_string` applied to a type that implements `Display` in `{name}!` args"), - "use this", - format!( - "{}{:*>n_needed_derefs$}{receiver_snippet}", - if needs_ref { "&" } else { "" }, - "" - ), - Applicability::MachineApplicable, - ); + // Do not continue inlining (return false) in case + // * if we can't inline a numbered argument, e.g. `print!("{0} ...", foo.bar, ...)` + // * if allow_mixed_uninlined_format_args is false and this arg hasn't been inlined already + pos.kind != FormatArgPositionKind::Number + && (!self.ignore_mixed || matches!(arg.kind, FormatArgumentKind::Captured(_))) } } -} -fn format_arg_positions( - format_args: &rustc_ast::FormatArgs, -) -> impl Iterator { - format_args.template.iter().flat_map(|piece| match piece { - FormatArgsPiece::Placeholder(placeholder) => { - let mut positions = ArrayVec::<_, 3>::new(); + fn check_format_in_format_args(&self, name: Symbol, arg: &Expr<'_>) { + let expn_data = arg.span.ctxt().outer_expn_data(); + if expn_data.call_site.from_expansion() { + return; + } + let Some(mac_id) = expn_data.macro_def_id else { return }; + if !self.cx.tcx.is_diagnostic_item(sym::format_macro, mac_id) { + return; + } + span_lint_and_then( + self.cx, + FORMAT_IN_FORMAT_ARGS, + self.macro_call.span, + &format!("`format!` in `{name}!` args"), + |diag| { + diag.help(format!( + "combine the `format!(..)` arguments with the outer `{name}!(..)` call" + )); + diag.help("or consider changing `format!` to `format_args!`"); + }, + ); + } - positions.push((&placeholder.argument, FormatParamUsage::Argument)); - if let Some(FormatCount::Argument(position)) = &placeholder.format_options.width { - positions.push((position, FormatParamUsage::Width)); - } - if let Some(FormatCount::Argument(position)) = &placeholder.format_options.precision { - positions.push((position, FormatParamUsage::Precision)); + fn check_to_string_in_format_args(&self, name: Symbol, value: &Expr<'_>) { + let cx = self.cx; + if !value.span.from_expansion() + && let ExprKind::MethodCall(_, receiver, [], to_string_span) = value.kind + && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id) + && is_diag_trait_item(cx, method_def_id, sym::ToString) + && let receiver_ty = cx.typeck_results().expr_ty(receiver) + && let Some(display_trait_id) = cx.tcx.get_diagnostic_item(sym::Display) + && let (n_needed_derefs, target) = + count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter()) + && implements_trait(cx, target, display_trait_id, &[]) + && let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait() + && let Some(receiver_snippet) = snippet_opt(cx, receiver.span) + { + let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]); + if n_needed_derefs == 0 && !needs_ref { + span_lint_and_sugg( + cx, + TO_STRING_IN_FORMAT_ARGS, + to_string_span.with_lo(receiver.span.hi()), + &format!("`to_string` applied to a type that implements `Display` in `{name}!` args"), + "remove this", + String::new(), + Applicability::MachineApplicable, + ); + } else { + span_lint_and_sugg( + cx, + TO_STRING_IN_FORMAT_ARGS, + value.span, + &format!("`to_string` applied to a type that implements `Display` in `{name}!` args"), + "use this", + format!( + "{}{:*>n_needed_derefs$}{receiver_snippet}", + if needs_ref { "&" } else { "" }, + "" + ), + Applicability::MachineApplicable, + ); } + } + } - positions - }, - FormatArgsPiece::Literal(_) => ArrayVec::new(), - }) -} + fn format_arg_positions(&self) -> impl Iterator { + self.format_args.template.iter().flat_map(|piece| match piece { + FormatArgsPiece::Placeholder(placeholder) => { + let mut positions = ArrayVec::<_, 3>::new(); -/// Returns true if the format argument at `index` is referred to by multiple format params -fn is_aliased(format_args: &rustc_ast::FormatArgs, index: usize) -> bool { - format_arg_positions(format_args) - .filter(|(position, _)| position.index == Ok(index)) - .at_most_one() - .is_err() + positions.push((&placeholder.argument, FormatParamUsage::Argument)); + if let Some(FormatCount::Argument(position)) = &placeholder.format_options.width { + positions.push((position, FormatParamUsage::Width)); + } + if let Some(FormatCount::Argument(position)) = &placeholder.format_options.precision { + positions.push((position, FormatParamUsage::Precision)); + } + + positions + }, + FormatArgsPiece::Literal(_) => ArrayVec::new(), + }) + } + + /// Returns true if the format argument at `index` is referred to by multiple format params + fn is_aliased(&self, index: usize) -> bool { + self.format_arg_positions() + .filter(|(position, _)| position.index == Ok(index)) + .at_most_one() + .is_err() + } } fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>) diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index 9360eb1fa91ad..93517076cda01 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -7,7 +7,7 @@ use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{sym, Symbol}; declare_clippy_lint! { /// ### What it does @@ -119,123 +119,132 @@ impl<'tcx> LateLintPass<'tcx> for FormatImpl { } fn check_impl_item_post(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { - // Assume no nested Impl of Debug and Display within eachother + // Assume no nested Impl of Debug and Display within each other if is_format_trait_impl(cx, impl_item).is_some() { self.format_trait_impl = None; } } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - let Some(format_trait_impl) = self.format_trait_impl else { - return; - }; - - if format_trait_impl.name == sym::Display { - check_to_string_in_display(cx, expr); + if let Some(format_trait_impl) = self.format_trait_impl { + let linter = FormatImplExpr { + cx, + expr, + format_trait_impl, + }; + linter.check_to_string_in_display(); + linter.check_self_in_format_args(); + linter.check_print_in_format_impl(); } - - check_self_in_format_args(cx, expr, format_trait_impl); - check_print_in_format_impl(cx, expr, format_trait_impl); } } -fn check_to_string_in_display(cx: &LateContext<'_>, expr: &Expr<'_>) { - if let ExprKind::MethodCall(path, self_arg, ..) = expr.kind - // Get the hir_id of the object we are calling the method on - // Is the method to_string() ? - && path.ident.name == sym::to_string - // Is the method a part of the ToString trait? (i.e. not to_string() implemented - // separately) - && let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) - && is_diag_trait_item(cx, expr_def_id, sym::ToString) - // Is the method is called on self - && let ExprKind::Path(QPath::Resolved(_, path)) = self_arg.kind - && let [segment] = path.segments - && segment.ident.name == kw::SelfLower - { - span_lint( - cx, - RECURSIVE_FORMAT_IMPL, - expr.span, - "using `self.to_string` in `fmt::Display` implementation will cause infinite recursion", - ); - } +struct FormatImplExpr<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + format_trait_impl: FormatTraitNames, } -fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, impl_trait: FormatTraitNames) { - // Check each arg in format calls - do we ever use Display on self (directly or via deref)? - if let Some(outer_macro) = root_macro_call_first_node(cx, expr) - && let macro_def_id = outer_macro.def_id - && is_format_macro(cx, macro_def_id) - && let Some(format_args) = find_format_args(cx, expr, outer_macro.expn) - { - for piece in &format_args.template { - if let FormatArgsPiece::Placeholder(placeholder) = piece - && let trait_name = match placeholder.format_trait { - FormatTrait::Display => sym::Display, - FormatTrait::Debug => sym::Debug, - FormatTrait::LowerExp => sym!(LowerExp), - FormatTrait::UpperExp => sym!(UpperExp), - FormatTrait::Octal => sym!(Octal), - FormatTrait::Pointer => sym::Pointer, - FormatTrait::Binary => sym!(Binary), - FormatTrait::LowerHex => sym!(LowerHex), - FormatTrait::UpperHex => sym!(UpperHex), +impl<'a, 'tcx> FormatImplExpr<'a, 'tcx> { + fn check_to_string_in_display(&self) { + if self.format_trait_impl.name == sym::Display + && let ExprKind::MethodCall(path, self_arg, ..) = self.expr.kind + // Get the hir_id of the object we are calling the method on + // Is the method to_string() ? + && path.ident.name == sym::to_string + // Is the method a part of the ToString trait? (i.e. not to_string() implemented + // separately) + && let Some(expr_def_id) = self.cx.typeck_results().type_dependent_def_id(self.expr.hir_id) + && is_diag_trait_item(self.cx, expr_def_id, sym::ToString) + // Is the method is called on self + && let ExprKind::Path(QPath::Resolved(_, path)) = self_arg.kind + && let [segment] = path.segments + && segment.ident.name == kw::SelfLower + { + span_lint( + self.cx, + RECURSIVE_FORMAT_IMPL, + self.expr.span, + "using `self.to_string` in `fmt::Display` implementation will cause infinite recursion", + ); + } + } + + fn check_self_in_format_args(&self) { + // Check each arg in format calls - do we ever use Display on self (directly or via deref)? + if let Some(outer_macro) = root_macro_call_first_node(self.cx, self.expr) + && let macro_def_id = outer_macro.def_id + && is_format_macro(self.cx, macro_def_id) + && let Some(format_args) = find_format_args(self.cx, self.expr, outer_macro.expn) + { + for piece in &format_args.template { + if let FormatArgsPiece::Placeholder(placeholder) = piece + && let trait_name = match placeholder.format_trait { + FormatTrait::Display => sym::Display, + FormatTrait::Debug => sym::Debug, + FormatTrait::LowerExp => sym!(LowerExp), + FormatTrait::UpperExp => sym!(UpperExp), + FormatTrait::Octal => sym!(Octal), + FormatTrait::Pointer => sym::Pointer, + FormatTrait::Binary => sym!(Binary), + FormatTrait::LowerHex => sym!(LowerHex), + FormatTrait::UpperHex => sym!(UpperHex), + } + && trait_name == self.format_trait_impl.name + && let Ok(index) = placeholder.argument.index + && let Some(arg) = format_args.arguments.all_args().get(index) + && let Ok(arg_expr) = find_format_arg_expr(self.expr, arg) + { + self.check_format_arg_self(arg_expr); } - && trait_name == impl_trait.name - && let Ok(index) = placeholder.argument.index - && let Some(arg) = format_args.arguments.all_args().get(index) - && let Ok(arg_expr) = find_format_arg_expr(expr, arg) - { - check_format_arg_self(cx, expr.span, arg_expr, impl_trait); } } } -} -fn check_format_arg_self(cx: &LateContext<'_>, span: Span, arg: &Expr<'_>, impl_trait: FormatTraitNames) { - // Handle multiple dereferencing of references e.g. &&self - // Handle dereference of &self -> self that is equivalent (i.e. via *self in fmt() impl) - // Since the argument to fmt is itself a reference: &self - let reference = peel_ref_operators(cx, arg); - let map = cx.tcx.hir(); - // Is the reference self? - if path_to_local(reference).map(|x| map.name(x)) == Some(kw::SelfLower) { - let FormatTraitNames { name, .. } = impl_trait; - span_lint( - cx, - RECURSIVE_FORMAT_IMPL, - span, - &format!("using `self` as `{name}` in `impl {name}` will cause infinite recursion"), - ); + fn check_format_arg_self(&self, arg: &Expr<'_>) { + // Handle multiple dereferencing of references e.g. &&self + // Handle dereference of &self -> self that is equivalent (i.e. via *self in fmt() impl) + // Since the argument to fmt is itself a reference: &self + let reference = peel_ref_operators(self.cx, arg); + let map = self.cx.tcx.hir(); + // Is the reference self? + if path_to_local(reference).map(|x| map.name(x)) == Some(kw::SelfLower) { + let FormatTraitNames { name, .. } = self.format_trait_impl; + span_lint( + self.cx, + RECURSIVE_FORMAT_IMPL, + self.expr.span, + &format!("using `self` as `{name}` in `impl {name}` will cause infinite recursion"), + ); + } } -} -fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait: FormatTraitNames) { - if let Some(macro_call) = root_macro_call_first_node(cx, expr) - && let Some(name) = cx.tcx.get_diagnostic_name(macro_call.def_id) - { - let replacement = match name { - sym::print_macro | sym::eprint_macro => "write", - sym::println_macro | sym::eprintln_macro => "writeln", - _ => return, - }; + fn check_print_in_format_impl(&self) { + if let Some(macro_call) = root_macro_call_first_node(self.cx, self.expr) + && let Some(name) = self.cx.tcx.get_diagnostic_name(macro_call.def_id) + { + let replacement = match name { + sym::print_macro | sym::eprint_macro => "write", + sym::println_macro | sym::eprintln_macro => "writeln", + _ => return, + }; - let name = name.as_str().strip_suffix("_macro").unwrap(); + let name = name.as_str().strip_suffix("_macro").unwrap(); - span_lint_and_sugg( - cx, - PRINT_IN_FORMAT_IMPL, - macro_call.span, - &format!("use of `{name}!` in `{}` impl", impl_trait.name), - "replace with", - if let Some(formatter_name) = impl_trait.formatter_name { - format!("{replacement}!({formatter_name}, ..)") - } else { - format!("{replacement}!(..)") - }, - Applicability::HasPlaceholders, - ); + span_lint_and_sugg( + self.cx, + PRINT_IN_FORMAT_IMPL, + macro_call.span, + &format!("use of `{name}!` in `{}` impl", self.format_trait_impl.name), + "replace with", + if let Some(formatter_name) = self.format_trait_impl.formatter_name { + format!("{replacement}!({formatter_name}, ..)") + } else { + format!("{replacement}!(..)") + }, + Applicability::HasPlaceholders, + ); + } } } diff --git a/clippy_lints/src/implied_bounds_in_impls.rs b/clippy_lints/src/implied_bounds_in_impls.rs index fab8ffedb9493..74582f7f1de23 100644 --- a/clippy_lints/src/implied_bounds_in_impls.rs +++ b/clippy_lints/src/implied_bounds_in_impls.rs @@ -1,11 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use rustc_errors::{Applicability, SuggestionStyle}; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::FnKind; +use rustc_hir::def_id::DefId; use rustc_hir::{ - Body, FnDecl, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind, ItemKind, TraitBoundModifier, TraitItem, - TraitItemKind, TyKind, + GenericArg, GenericBound, GenericBounds, ItemKind, PredicateOrigin, TraitBoundModifier, TyKind, TypeBinding, + WherePredicate, }; use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; @@ -50,20 +49,17 @@ declare_clippy_lint! { } declare_lint_pass!(ImpliedBoundsInImpls => [IMPLIED_BOUNDS_IN_IMPLS]); -#[allow(clippy::too_many_arguments)] fn emit_lint( cx: &LateContext<'_>, poly_trait: &rustc_hir::PolyTraitRef<'_>, - opaque_ty: &rustc_hir::OpaqueTy<'_>, + bounds: GenericBounds<'_>, index: usize, - // The bindings that were implied + // The bindings that were implied, used for suggestion purposes since removing a bound with associated types + // means we might need to then move it to a different bound implied_bindings: &[rustc_hir::TypeBinding<'_>], - // The original bindings that `implied_bindings` are implied from - implied_by_bindings: &[rustc_hir::TypeBinding<'_>], - implied_by_args: &[GenericArg<'_>], - implied_by_span: Span, + bound: &ImplTraitBound<'_>, ) { - let implied_by = snippet(cx, implied_by_span, ".."); + let implied_by = snippet(cx, bound.span, ".."); span_lint_and_then( cx, @@ -75,10 +71,10 @@ fn emit_lint( // to include the `+` token that is ahead or behind, // so we don't end up with something like `impl + B` or `impl A + ` - let implied_span_extended = if let Some(next_bound) = opaque_ty.bounds.get(index + 1) { + let implied_span_extended = if let Some(next_bound) = bounds.get(index + 1) { poly_trait.span.to(next_bound.span().shrink_to_lo()) } else if index > 0 - && let Some(prev_bound) = opaque_ty.bounds.get(index - 1) + && let Some(prev_bound) = bounds.get(index - 1) { prev_bound.span().shrink_to_hi().to(poly_trait.span.shrink_to_hi()) } else { @@ -93,17 +89,17 @@ fn emit_lint( // If we're going to suggest removing `Deref<..>`, we'll need to put `` on `DerefMut` let omitted_assoc_tys: Vec<_> = implied_bindings .iter() - .filter(|binding| !implied_by_bindings.iter().any(|b| b.ident == binding.ident)) + .filter(|binding| !bound.bindings.iter().any(|b| b.ident == binding.ident)) .collect(); if !omitted_assoc_tys.is_empty() { // `<>` needs to be added if there aren't yet any generic arguments or bindings - let needs_angle_brackets = implied_by_args.is_empty() && implied_by_bindings.is_empty(); - let insert_span = match (implied_by_args, implied_by_bindings) { + let needs_angle_brackets = bound.args.is_empty() && bound.bindings.is_empty(); + let insert_span = match (bound.args, bound.bindings) { ([.., arg], [.., binding]) => arg.span().max(binding.span).shrink_to_hi(), ([.., arg], []) => arg.span().shrink_to_hi(), ([], [.., binding]) => binding.span.shrink_to_hi(), - ([], []) => implied_by_span.shrink_to_hi(), + ([], []) => bound.span.shrink_to_hi(), }; let mut associated_tys_sugg = if needs_angle_brackets { @@ -223,111 +219,135 @@ fn is_same_generics<'tcx>( }) } -fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) { - if let FnRetTy::Return(ty) = decl.output - &&let TyKind::OpaqueDef(item_id, ..) = ty.kind - && let item = cx.tcx.hir().item(item_id) - && let ItemKind::OpaqueTy(opaque_ty) = item.kind - // Very often there is only a single bound, e.g. `impl Deref<..>`, in which case - // we can avoid doing a bunch of stuff unnecessarily. - && opaque_ty.bounds.len() > 1 - { - // Get all the (implied) trait predicates in the bounds. - // For `impl Deref + DerefMut` this will contain [`Deref`]. - // The implied `Deref` comes from `DerefMut` because `trait DerefMut: Deref {}`. - // N.B. (G)ATs are fine to disregard, because they must be the same for all of its supertraits. - // Example: - // `impl Deref + DerefMut` is not allowed. - // `DerefMut::Target` needs to match `Deref::Target`. - let implied_bounds: Vec<_> = opaque_ty - .bounds - .iter() - .filter_map(|bound| { - if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound - && let [.., path] = poly_trait.trait_ref.path.segments - && poly_trait.bound_generic_params.is_empty() - && let Some(trait_def_id) = path.res.opt_def_id() - && let predicates = cx.tcx.super_predicates_of(trait_def_id).predicates - && !predicates.is_empty() - // If the trait has no supertrait, there is nothing to add. - { - Some((bound.span(), path, predicates, trait_def_id)) - } else { - None - } - }) - .collect(); +struct ImplTraitBound<'tcx> { + /// The span of the bound in the `impl Trait` type + span: Span, + /// The predicates defined in the trait referenced by this bound. This also contains the actual + /// supertrait bounds + predicates: &'tcx [(ty::Clause<'tcx>, Span)], + /// The `DefId` of the trait being referenced by this bound + trait_def_id: DefId, + /// The generic arguments on the `impl Trait` bound + args: &'tcx [GenericArg<'tcx>], + /// The associated types on this bound + bindings: &'tcx [TypeBinding<'tcx>], +} - // Lint all bounds in the `impl Trait` type that are also in the `implied_bounds` vec. - // This involves some extra logic when generic arguments are present, since - // simply comparing trait `DefId`s won't be enough. We also need to compare the generics. - for (index, bound) in opaque_ty.bounds.iter().enumerate() { +/// Given an `impl Trait` type, gets all the supertraits from each bound ("implied bounds"). +/// +/// For `impl Deref + DerefMut + Eq` this returns `[Deref, PartialEq]`. +/// The `Deref` comes from `DerefMut` because `trait DerefMut: Deref {}`, and `PartialEq` comes from +/// `Eq`. +fn collect_supertrait_bounds<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds<'tcx>) -> Vec> { + bounds + .iter() + .filter_map(|bound| { if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound && let [.., path] = poly_trait.trait_ref.path.segments - && let implied_args = path.args.map_or([].as_slice(), |a| a.args) - && let implied_bindings = path.args.map_or([].as_slice(), |a| a.bindings) - && let Some(def_id) = poly_trait.trait_ref.path.res.opt_def_id() - && let Some((implied_by_span, implied_by_args, implied_by_bindings)) = - implied_bounds - .iter() - .find_map(|&(span, implied_by_path, preds, implied_by_def_id)| { - let implied_by_args = implied_by_path.args.map_or([].as_slice(), |a| a.args); - let implied_by_bindings = implied_by_path.args.map_or([].as_slice(), |a| a.bindings); + && poly_trait.bound_generic_params.is_empty() + && let Some(trait_def_id) = path.res.opt_def_id() + && let predicates = cx.tcx.super_predicates_of(trait_def_id).predicates + // If the trait has no supertrait, there is no need to collect anything from that bound + && !predicates.is_empty() + { + Some(ImplTraitBound { + predicates, + args: path.args.map_or([].as_slice(), |p| p.args), + bindings: path.args.map_or([].as_slice(), |p| p.bindings), + trait_def_id, + span: bound.span(), + }) + } else { + None + } + }) + .collect() +} - preds.iter().find_map(|(clause, _)| { - if let ClauseKind::Trait(tr) = clause.kind().skip_binder() - && tr.def_id() == def_id - && is_same_generics( - cx.tcx, - tr.trait_ref.args, - implied_by_args, - implied_args, - implied_by_def_id, - def_id, - ) - { - Some((span, implied_by_args, implied_by_bindings)) - } else { - None - } - }) - }) +/// Given a bound in an `impl Trait` type, looks for a trait in the set of supertraits (previously +/// collected in [`collect_supertrait_bounds`]) that matches (same trait and generic arguments). +fn find_bound_in_supertraits<'a, 'tcx>( + cx: &LateContext<'tcx>, + trait_def_id: DefId, + args: &'tcx [GenericArg<'tcx>], + bounds: &'a [ImplTraitBound<'tcx>], +) -> Option<&'a ImplTraitBound<'tcx>> { + bounds.iter().find(|bound| { + bound.predicates.iter().any(|(clause, _)| { + if let ClauseKind::Trait(tr) = clause.kind().skip_binder() + && tr.def_id() == trait_def_id { - emit_lint( - cx, - poly_trait, - opaque_ty, - index, - implied_bindings, - implied_by_bindings, - implied_by_args, - implied_by_span, - ); + is_same_generics( + cx.tcx, + tr.trait_ref.args, + bound.args, + args, + bound.trait_def_id, + trait_def_id, + ) + } else { + false } + }) + }) +} + +fn check<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds<'tcx>) { + if bounds.len() == 1 { + // Very often there is only a single bound, e.g. `impl Deref<..>`, in which case + // we can avoid doing a bunch of stuff unnecessarily; there will trivially be + // no duplicate bounds + return; + } + + let supertraits = collect_supertrait_bounds(cx, bounds); + + // Lint all bounds in the `impl Trait` type that we've previously also seen in the set of + // supertraits of each of the bounds. + // This involves some extra logic when generic arguments are present, since + // simply comparing trait `DefId`s won't be enough. We also need to compare the generics. + for (index, bound) in bounds.iter().enumerate() { + if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound + && let [.., path] = poly_trait.trait_ref.path.segments + && let implied_args = path.args.map_or([].as_slice(), |a| a.args) + && let implied_bindings = path.args.map_or([].as_slice(), |a| a.bindings) + && let Some(def_id) = poly_trait.trait_ref.path.res.opt_def_id() + && let Some(bound) = find_bound_in_supertraits(cx, def_id, implied_args, &supertraits) + // If the implied bound has a type binding that also exists in the implied-by trait, + // then we shouldn't lint. See #11880 for an example. + && let assocs = cx.tcx.associated_items(bound.trait_def_id) + && !implied_bindings.iter().any(|binding| { + assocs + .filter_by_name_unhygienic(binding.ident.name) + .next() + .is_some_and(|assoc| assoc.kind == ty::AssocKind::Type) + }) + { + emit_lint(cx, poly_trait, bounds, index, implied_bindings, bound); } } } -impl LateLintPass<'_> for ImpliedBoundsInImpls { - fn check_fn( - &mut self, - cx: &LateContext<'_>, - _: FnKind<'_>, - decl: &FnDecl<'_>, - _: &Body<'_>, - _: Span, - _: LocalDefId, - ) { - check(cx, decl); - } - fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) { - if let TraitItemKind::Fn(sig, ..) = &item.kind { - check(cx, sig.decl); +impl<'tcx> LateLintPass<'tcx> for ImpliedBoundsInImpls { + fn check_generics(&mut self, cx: &LateContext<'tcx>, generics: &rustc_hir::Generics<'tcx>) { + for predicate in generics.predicates { + if let WherePredicate::BoundPredicate(predicate) = predicate + // In theory, the origin doesn't really matter, + // we *could* also lint on explicit where clauses written out by the user, + // not just impl trait desugared ones, but that contradicts with the lint name... + && let PredicateOrigin::ImplTrait = predicate.origin + { + check(cx, predicate.bounds); + } } } - fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &ImplItem<'_>) { - if let ImplItemKind::Fn(sig, ..) = &item.kind { - check(cx, sig.decl); + + fn check_ty(&mut self, cx: &LateContext<'_>, ty: &rustc_hir::Ty<'_>) { + if let TyKind::OpaqueDef(item_id, ..) = ty.kind + && let item = cx.tcx.hir().item(item_id) + && let ItemKind::OpaqueTy(opaque_ty) = item.kind + { + check(cx, opaque_ty.bounds); } } } diff --git a/clippy_lints/src/incompatible_msrv.rs b/clippy_lints/src/incompatible_msrv.rs index f2f0e7d426628..cd000fcd18449 100644 --- a/clippy_lints/src/incompatible_msrv.rs +++ b/clippy_lints/src/incompatible_msrv.rs @@ -1,14 +1,15 @@ use clippy_config::msrvs::Msrv; use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_in_test_function; use rustc_attr::{StabilityLevel, StableSince}; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; use rustc_semver::RustcVersion; use rustc_session::impl_lint_pass; use rustc_span::def_id::DefId; -use rustc_span::Span; +use rustc_span::{ExpnKind, Span}; declare_clippy_lint! { /// ### What it does @@ -81,13 +82,18 @@ impl IncompatibleMsrv { version } - fn emit_lint_if_under_msrv(&mut self, cx: &LateContext<'_>, def_id: DefId, span: Span) { + fn emit_lint_if_under_msrv(&mut self, cx: &LateContext<'_>, def_id: DefId, node: HirId, span: Span) { if def_id.is_local() { // We don't check local items since their MSRV is supposed to always be valid. return; } let version = self.get_def_id_version(cx.tcx, def_id); - if self.msrv.meets(version) { + if self.msrv.meets(version) || is_in_test_function(cx.tcx, node) { + return; + } + if let ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) = span.ctxt().outer_expn_data().kind { + // Desugared expressions get to cheat and stability is ignored. + // Intentionally not using `.from_expansion()`, since we do still care about macro expansions return; } self.emit_lint_for(cx, span, version); @@ -117,14 +123,14 @@ impl<'tcx> LateLintPass<'tcx> for IncompatibleMsrv { match expr.kind { ExprKind::MethodCall(_, _, _, span) => { if let Some(method_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { - self.emit_lint_if_under_msrv(cx, method_did, span); + self.emit_lint_if_under_msrv(cx, method_did, expr.hir_id, span); } }, ExprKind::Call(call, [_]) => { if let ExprKind::Path(qpath) = call.kind && let Some(path_def_id) = cx.qpath_res(&qpath, call.hir_id).opt_def_id() { - self.emit_lint_if_under_msrv(cx, path_def_id, call.span); + self.emit_lint_if_under_msrv(cx, path_def_id, expr.hir_id, call.span); } }, _ => {}, diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index 41e9d5b1c2e9d..5b5eb355f86cd 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -255,7 +255,9 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> { && let hir::Node::Expr(maybe_addrof_expr) = cx.tcx.parent_hir_node(parent_id) && let hir::ExprKind::AddrOf(_kind, hir::Mutability::Not, _inner_expr) = maybe_addrof_expr.kind { - use_info.index_use.push((index_value, cx.tcx.hir().span(parent_expr.hir_id))); + use_info + .index_use + .push((index_value, cx.tcx.hir().span(parent_expr.hir_id))); return; } diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs index 391db0b0df726..35fcd8cdd3547 100644 --- a/clippy_lints/src/indexing_slicing.rs +++ b/clippy_lints/src/indexing_slicing.rs @@ -174,6 +174,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { // only `usize` index is legal in rust array index // leave other type to rustc if let Constant::Int(off) = constant + && off <= usize::MAX as u128 && let ty::Uint(utype) = cx.typeck_results().expr_ty(index).kind() && *utype == ty::UintTy::Usize && let ty::Array(_, s) = ty.kind() diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs index 276c1abb60cd5..0b4c416d94db0 100644 --- a/clippy_lints/src/item_name_repetitions.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -385,7 +385,6 @@ impl LateLintPass<'_> for ItemNameRepetitions { assert!(last.is_some()); } - #[expect(clippy::similar_names)] fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { let item_name = item.ident.name.as_str(); let item_camel = to_camel_case(item_name); diff --git a/clippy_lints/src/iter_not_returning_iterator.rs b/clippy_lints/src/iter_not_returning_iterator.rs index b9fad726511c5..32ae6be568735 100644 --- a/clippy_lints/src/iter_not_returning_iterator.rs +++ b/clippy_lints/src/iter_not_returning_iterator.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::get_parent_node; use clippy_utils::ty::implements_trait; use rustc_hir::def_id::LocalDefId; use rustc_hir::{FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; @@ -56,8 +55,8 @@ impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator { let name = item.ident.name.as_str(); if matches!(name, "iter" | "iter_mut") && !matches!( - get_parent_node(cx.tcx, item.hir_id()), - Some(Node::Item(Item { kind: ItemKind::Impl(i), .. })) if i.of_trait.is_some() + cx.tcx.parent_hir_node(item.hir_id()), + Node::Item(Item { kind: ItemKind::Impl(i), .. }) if i.of_trait.is_some() ) { if let ImplItemKind::Fn(fn_sig, _) = &item.kind { diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 14bd82f9c97ea..76e759683145e 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -14,7 +14,7 @@ clippy::missing_docs_in_private_items, clippy::must_use_candidate, rustc::diagnostic_outside_of_impl, - rustc::untranslatable_diagnostic, + rustc::untranslatable_diagnostic )] #![warn(trivial_casts, trivial_numeric_casts)] // warn on lints, that are included in `rust-lang/rust`s bootstrap @@ -231,6 +231,7 @@ mod missing_trait_methods; mod mixed_read_write_in_expression; mod module_style; mod multi_assignments; +mod multiple_bound_locations; mod multiple_unsafe_ops_per_block; mod mut_key; mod mut_mut; @@ -1067,7 +1068,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| { Box::new(single_call_fn::SingleCallFn { avoid_breaking_exported_api, - def_id_to_usage: rustc_data_structures::fx::FxHashMap::default(), + def_id_to_usage: rustc_data_structures::fx::FxIndexMap::default(), }) }); store.register_early_pass(move || { @@ -1116,6 +1117,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { }); store.register_late_pass(move |_| Box::new(incompatible_msrv::IncompatibleMsrv::new(msrv()))); store.register_late_pass(|_| Box::new(to_string_trait_impl::ToStringTraitImpl)); + store.register_early_pass(|| Box::new(multiple_bound_locations::MultipleBoundLocations)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/loops/infinite_loop.rs b/clippy_lints/src/loops/infinite_loop.rs index 5e099f1e76f86..5b5bb88c17908 100644 --- a/clippy_lints/src/loops/infinite_loop.rs +++ b/clippy_lints/src/loops/infinite_loop.rs @@ -1,17 +1,18 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{fn_def_id, is_lint_allowed}; +use clippy_utils::{fn_def_id, is_from_proc_macro, is_lint_allowed}; use hir::intravisit::{walk_expr, Visitor}; use hir::{Expr, ExprKind, FnRetTy, FnSig, Node}; use rustc_ast::Label; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_lint::LateContext; +use rustc_lint::{LateContext, LintContext}; +use rustc_middle::lint::in_external_macro; use super::INFINITE_LOOP; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, - expr: &Expr<'_>, + expr: &Expr<'tcx>, loop_block: &'tcx hir::Block<'_>, label: Option