From 980ace19e50878ef17cf9d557c378bf7053ebcae Mon Sep 17 00:00:00 2001 From: FelixMaetzler Date: Mon, 4 Dec 2023 13:11:03 +0100 Subject: [PATCH 01/53] works for 0 and unsigned ints --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 26 +++++++++++ clippy_lints/src/methods/unnecessary_min.rs | 51 +++++++++++++++++++++ tests/ui/unnecessary_min.fixed | 34 ++++++++++++++ tests/ui/unnecessary_min.rs | 34 ++++++++++++++ tests/ui/unnecessary_min.stderr | 29 ++++++++++++ 7 files changed, 176 insertions(+) create mode 100644 clippy_lints/src/methods/unnecessary_min.rs create mode 100644 tests/ui/unnecessary_min.fixed create mode 100644 tests/ui/unnecessary_min.rs create mode 100644 tests/ui/unnecessary_min.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 7faf145dc802..a57beee6e969 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5602,6 +5602,7 @@ Released 2018-09-13 [`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 [`unnecessary_map_on_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_map_on_constructor +[`unnecessary_min`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_min [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation [`unnecessary_owned_empty_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_owned_empty_strings diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 682249f13c09..436764320d61 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -442,6 +442,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::UNNECESSARY_JOIN_INFO, crate::methods::UNNECESSARY_LAZY_EVALUATIONS_INFO, crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO, + crate::methods::UNNECESSARY_MIN_INFO, crate::methods::UNNECESSARY_SORT_BY_INFO, crate::methods::UNNECESSARY_TO_OWNED_INFO, crate::methods::UNWRAP_OR_DEFAULT_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 25c681bb9d96..85269056de25 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -109,6 +109,7 @@ mod unnecessary_iter_cloned; mod unnecessary_join; mod unnecessary_lazy_eval; mod unnecessary_literal_unwrap; +mod unnecessary_min; mod unnecessary_sort_by; mod unnecessary_to_owned; mod unwrap_expect_used; @@ -3752,6 +3753,29 @@ declare_clippy_lint! { "using `Option.map_or(Err(_), Ok)`, which is more succinctly expressed as `Option.ok_or(_)`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for unnecessary calls to min() + /// + /// ### Why is this bad? + /// + /// In these cases it is not necessary to call min() + /// ### Example + /// ```no_run + /// // example code where clippy issues a warning + /// let _ = 0.min(7_u32); + /// ``` + /// Use instead: + /// ```no_run + /// // example code which does not raise clippy warning + /// let _ = 7; + /// ``` + #[clippy::version = "1.76.0"] + pub UNNECESSARY_MIN, + complexity, + "default lint description" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3903,6 +3927,7 @@ impl_lint_pass!(Methods => [ UNNECESSARY_FALLIBLE_CONVERSIONS, JOIN_ABSOLUTE_PATHS, OPTION_MAP_OR_ERR_OK, + UNNECESSARY_MIN, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4184,6 +4209,7 @@ impl Methods { Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2), _ => {}, }, + ("min", [arg]) => unnecessary_min::check(cx, expr, arg), ("drain", ..) => { if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.hir().get_parent(expr.hir_id) && matches!(kind, StmtKind::Semi(_)) diff --git a/clippy_lints/src/methods/unnecessary_min.rs b/clippy_lints/src/methods/unnecessary_min.rs new file mode 100644 index 000000000000..312e691c145c --- /dev/null +++ b/clippy_lints/src/methods/unnecessary_min.rs @@ -0,0 +1,51 @@ +use super::UNNECESSARY_MIN; +use clippy_utils::diagnostics::span_lint_and_sugg; + +use hir::{Expr, ExprKind}; + +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::ty; + +pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, _: &'tcx Expr<'_>) { + let ty = cx.typeck_results().expr_ty(expr); + if !matches!(ty.kind(), ty::Uint(_)) { + return; + } + match expr.kind { + hir::ExprKind::MethodCall(_, left1, right1, _) => { + let left = left1.kind; + let right = right1[0].kind; + if let ExprKind::Lit(test) = left { + if let LitKind::Int(0, _) = test.node { + span_lint_and_sugg( + cx, + UNNECESSARY_MIN, + expr.span, + "this operation has no effect", + "try: ", + "0".to_string(), + Applicability::MachineApplicable, + ); + } + } + + if let ExprKind::Lit(test) = right { + if let LitKind::Int(0, _) = test.node { + span_lint_and_sugg( + cx, + UNNECESSARY_MIN, + expr.span, + "this operation has no effect", + "try: ", + "0".to_string(), + Applicability::MachineApplicable, + ); + } + } + }, + _ => {}, + }; +} diff --git a/tests/ui/unnecessary_min.fixed b/tests/ui/unnecessary_min.fixed new file mode 100644 index 000000000000..a43937507135 --- /dev/null +++ b/tests/ui/unnecessary_min.fixed @@ -0,0 +1,34 @@ +#![allow(unused)] +#![warn(clippy::unnecessary_min)] + +fn main() { + const A: isize = 42; + const B: isize = 69; + let _ = A.min(B); // Both are constants + let _ = 6_i32.min(9); // Both are Literals + let _ = 6.min(7_u8); // Both are Literals + + let _ = 0; // unsigned with zero + let _ = 0; // unsigned with zero + + let _ = i32::MIN.min(42); // singed MIN + let _ = 42.min(i32::MIN); // singed MIN + + let _ = i32::MAX.min(42); // singed MAX + let _ = 42.min(i32::MAX); // singed MAX + + let _ = 0; // unsigned with zero and function + let _ = 0; // unsigned with zero and function + + let _ = i64::MIN.min(test_i64()); // signed with MIN and function + let _ = test_i64().min(i64::MIN); // signed with MIN and function + + let _ = i64::MAX.min(test_i64()); // signed with MAX and function + let _ = test_i64().min(i64::MAX); // signed with MAX and function +} +fn test_usize() -> usize { + 42 +} +fn test_i64() -> i64 { + 42 +} diff --git a/tests/ui/unnecessary_min.rs b/tests/ui/unnecessary_min.rs new file mode 100644 index 000000000000..999c169b338d --- /dev/null +++ b/tests/ui/unnecessary_min.rs @@ -0,0 +1,34 @@ +#![allow(unused)] +#![warn(clippy::unnecessary_min)] + +fn main() { + const A: isize = 42; + const B: isize = 69; + let _ = A.min(B); // Both are constants + let _ = 6_i32.min(9); // Both are Literals + let _ = 6.min(7_u8); // Both are Literals + + let _ = 0.min(7_u8); // unsigned with zero + let _ = 7.min(0_u32); // unsigned with zero + + let _ = i32::MIN.min(42); // singed MIN + let _ = 42.min(i32::MIN); // singed MIN + + let _ = i32::MAX.min(42); // singed MAX + let _ = 42.min(i32::MAX); // singed MAX + + let _ = 0.min(test_usize()); // unsigned with zero and function + let _ = test_usize().min(0); // unsigned with zero and function + + let _ = i64::MIN.min(test_i64()); // signed with MIN and function + let _ = test_i64().min(i64::MIN); // signed with MIN and function + + let _ = i64::MAX.min(test_i64()); // signed with MAX and function + let _ = test_i64().min(i64::MAX); // signed with MAX and function +} +fn test_usize() -> usize { + 42 +} +fn test_i64() -> i64 { + 42 +} diff --git a/tests/ui/unnecessary_min.stderr b/tests/ui/unnecessary_min.stderr new file mode 100644 index 000000000000..d3e15693ec83 --- /dev/null +++ b/tests/ui/unnecessary_min.stderr @@ -0,0 +1,29 @@ +error: this operation has no effect + --> $DIR/unnecessary_min.rs:11:13 + | +LL | let _ = 0.min(7_u8); // unsigned with zero + | ^^^^^^^^^^^ help: try: : `0` + | + = note: `-D clippy::unnecessary-min` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_min)]` + +error: this operation has no effect + --> $DIR/unnecessary_min.rs:12:13 + | +LL | let _ = 7.min(0_u32); // unsigned with zero + | ^^^^^^^^^^^^ help: try: : `0` + +error: this operation has no effect + --> $DIR/unnecessary_min.rs:20:13 + | +LL | let _ = 0.min(test_usize()); // unsigned with zero and function + | ^^^^^^^^^^^^^^^^^^^ help: try: : `0` + +error: this operation has no effect + --> $DIR/unnecessary_min.rs:21:13 + | +LL | let _ = test_usize().min(0); // unsigned with zero and function + | ^^^^^^^^^^^^^^^^^^^ help: try: : `0` + +error: aborting due to 4 previous errors + From 6db10d73e6875ecab89bcd94fdae747d6b212610 Mon Sep 17 00:00:00 2001 From: FelixMaetzler Date: Mon, 4 Dec 2023 20:40:39 +0100 Subject: [PATCH 02/53] lint works if both are known at compiletime --- clippy_lints/src/methods/unnecessary_min.rs | 190 ++++++++++++++++---- tests/ui/unnecessary_min.fixed | 29 ++- tests/ui/unnecessary_min.rs | 21 ++- tests/ui/unnecessary_min.stderr | 38 ++-- 4 files changed, 219 insertions(+), 59 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_min.rs b/clippy_lints/src/methods/unnecessary_min.rs index 312e691c145c..2205e14cf3bc 100644 --- a/clippy_lints/src/methods/unnecessary_min.rs +++ b/clippy_lints/src/methods/unnecessary_min.rs @@ -1,51 +1,179 @@ +use std::cmp::Ordering; + use super::UNNECESSARY_MIN; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::source::snippet; +use clippy_utils::{clip, int_bits, unsext}; use hir::{Expr, ExprKind}; - use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_middle::ty; + +use rustc_middle::ty::{self, IntTy}; +use rustc_span::Span; pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, _: &'tcx Expr<'_>) { + if both_are_constant(cx, expr) { + return; + } + let (left, right) = extract_both(expr); let ty = cx.typeck_results().expr_ty(expr); + + //------- if !matches!(ty.kind(), ty::Uint(_)) { return; } + if let ExprKind::Lit(test) = left { + if let LitKind::Int(0, _) = test.node { + span_lint_and_sugg( + cx, + UNNECESSARY_MIN, + expr.span, + "this operation has no effect", + "try: ", + "0".to_string(), + Applicability::MachineApplicable, + ); + } + } + + if let ExprKind::Lit(test) = right { + if let LitKind::Int(0, _) = test.node { + span_lint_and_sugg( + cx, + UNNECESSARY_MIN, + expr.span, + "this operation has no effect", + "try: ", + "0".to_string(), + Applicability::MachineApplicable, + ); + } + } +} +fn lint<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>, sugg: Span, other: Span) { + let msg = format!( + "{} is never greater than {} and has therefore no effect", + snippet(cx, sugg, "Not yet implemented"), + snippet(cx, other, "Not yet implemented") + ); + span_lint_and_sugg( + cx, + UNNECESSARY_MIN, + expr.span, + &msg, + "try", + snippet(cx, sugg, "Not yet implemented").to_string(), + Applicability::MachineApplicable, + ); +} + +fn extract_both<'tcx>(expr: &'tcx Expr<'_>) -> (ExprKind<'tcx>, ExprKind<'tcx>) { match expr.kind { hir::ExprKind::MethodCall(_, left1, right1, _) => { let left = left1.kind; let right = right1[0].kind; - if let ExprKind::Lit(test) = left { - if let LitKind::Int(0, _) = test.node { - span_lint_and_sugg( - cx, - UNNECESSARY_MIN, - expr.span, - "this operation has no effect", - "try: ", - "0".to_string(), - Applicability::MachineApplicable, - ); - } - } - - if let ExprKind::Lit(test) = right { - if let LitKind::Int(0, _) = test.node { - span_lint_and_sugg( - cx, - UNNECESSARY_MIN, - expr.span, - "this operation has no effect", - "try: ", - "0".to_string(), - Applicability::MachineApplicable, - ); - } - } + return (left, right); + }, + _ => unreachable!("this function gets only called on methods"), + } +} +fn try_to_eval<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> (Option>, Option>) { + let (left, right) = get_both_as_expr(expr); + + ( + (constant(cx, cx.typeck_results(), left)), + (constant(cx, cx.typeck_results(), right)), + ) +} +fn get_both_as_expr<'tcx>(expr: &'tcx Expr<'_>) -> (&'tcx Expr<'tcx>, &'tcx Expr<'tcx>) { + match expr.kind { + hir::ExprKind::MethodCall(_, left1, right1, _) => { + let left = left1; + let right = &right1[0]; + return (left, right); + }, + _ => unreachable!("this function gets only called on methods"), + } +} +#[derive(Debug)] +enum Extrema { + Minimum, + Maximum, +} +fn detect_extrema<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { + let ty = cx.typeck_results().expr_ty(expr); + + let cv = constant(cx, cx.typeck_results(), expr)?; + + match (ty.kind(), cv) { + (&ty::Uint(_), Constant::Int(0)) => Some(Extrema::Minimum), + (&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MIN >> (128 - int_bits(cx.tcx, ity)), ity) => { + Some(Extrema::Minimum) + }, + + (&ty::Int(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::MAX >> (128 - int_bits(cx.tcx, ity)), ity) => { + Some(Extrema::Maximum) }, - _ => {}, - }; + (&ty::Uint(uty), Constant::Int(i)) if i == clip(cx.tcx, u128::MAX, uty) => Some(Extrema::Maximum), + + _ => None, + } +} +fn cmp_for_signed(a: u128, b: u128, cx: &LateContext<'_>, ty: IntTy) -> Ordering { + let a_sign = Sign::from((a, cx, ty)); + let b_sign = Sign::from((b, cx, ty)); + // The Ordering of a signed integer interpreted as a unsigned is as follows: + // -1 b1111... uX::MAX + // iX::MIN b1000... + // iX::MAX b0111... + // 0 b0000... uX::MIN + match (a_sign, b_sign) { + (Sign::Positive, Sign::Positive) => a.cmp(&b), + (Sign::Positive, Sign::Negative) => Ordering::Greater, + (Sign::Negative, Sign::Positive) => Ordering::Less, + (Sign::Negative, Sign::Negative) => a.cmp(&b), + } +} +#[derive(Debug)] +enum Sign { + Positive, + Negative, +} +impl From<(u128, &LateContext<'_>, IntTy)> for Sign { + fn from(value: (u128, &LateContext<'_>, IntTy)) -> Self { + // The MSB decides wether the value has a negative sign in front of it or not + // the value 0 is counting as positive (or as non-negative) + let (value, cx, ity) = value; + // shifting the MSB from a iX (i32, i64, etc) to the MSB from a i128 + let value = value << (128 - int_bits(cx.tcx, ity)); + match (value.reverse_bits()) & 1_u128 { + 0 => Self::Positive, + 1 => Self::Negative, + _ => unreachable!("Bit can only be 0 or 1"), + } + } +} +fn both_are_constant<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { + let ty = cx.typeck_results().expr_ty(expr); + if let (Some(left), Some(right)) = try_to_eval(cx, expr) { + let ord = match (ty.kind(), left, right) { + (ty::Int(ty), Constant::Int(left), Constant::Int(right)) => cmp_for_signed(left, right, cx, *ty), + (ty::Uint(_), Constant::Int(left), Constant::Int(right)) => left.cmp(&right), + _ => return false, + }; + + let (sugg, other) = match ord { + Ordering::Less => (get_both_as_expr(expr).0.span, get_both_as_expr(expr).1.span), + Ordering::Equal => (get_both_as_expr(expr).1.span, get_both_as_expr(expr).0.span), + Ordering::Greater => (get_both_as_expr(expr).1.span, get_both_as_expr(expr).0.span), + }; + + lint(cx, expr, sugg, other); + return true; + } + false } diff --git a/tests/ui/unnecessary_min.fixed b/tests/ui/unnecessary_min.fixed index a43937507135..918481c8cb39 100644 --- a/tests/ui/unnecessary_min.fixed +++ b/tests/ui/unnecessary_min.fixed @@ -2,14 +2,23 @@ #![warn(clippy::unnecessary_min)] fn main() { - const A: isize = 42; - const B: isize = 69; - let _ = A.min(B); // Both are constants - let _ = 6_i32.min(9); // Both are Literals + /* + */ + const A: i64 = 45; + const B: i64 = -1; + const C: i64 = const_fn(B); + let _ = (A * B); // Both are constants + let _ = B; // Both are constants + let _ = B; // Both are constants + + let _ = (-6_i32); // Both are Literals + let _ = 6; // Both are Literals + + /* let _ = 6.min(7_u8); // Both are Literals - let _ = 0; // unsigned with zero - let _ = 0; // unsigned with zero + let _ = 0.min(7_u8); // unsigned with zero + let _ = 7.min(0_u32); // unsigned with zero let _ = i32::MIN.min(42); // singed MIN let _ = 42.min(i32::MIN); // singed MIN @@ -17,14 +26,15 @@ fn main() { let _ = i32::MAX.min(42); // singed MAX let _ = 42.min(i32::MAX); // singed MAX - let _ = 0; // unsigned with zero and function - let _ = 0; // unsigned with zero and function + let _ = 0.min(test_usize()); // unsigned with zero and function + let _ = test_usize().min(0); // unsigned with zero and function let _ = i64::MIN.min(test_i64()); // signed with MIN and function let _ = test_i64().min(i64::MIN); // signed with MIN and function let _ = i64::MAX.min(test_i64()); // signed with MAX and function let _ = test_i64().min(i64::MAX); // signed with MAX and function + */ } fn test_usize() -> usize { 42 @@ -32,3 +42,6 @@ fn test_usize() -> usize { fn test_i64() -> i64 { 42 } +const fn const_fn(input: i64) -> i64 { + -2 * input +} diff --git a/tests/ui/unnecessary_min.rs b/tests/ui/unnecessary_min.rs index 999c169b338d..cb375470a1c2 100644 --- a/tests/ui/unnecessary_min.rs +++ b/tests/ui/unnecessary_min.rs @@ -2,10 +2,19 @@ #![warn(clippy::unnecessary_min)] fn main() { - const A: isize = 42; - const B: isize = 69; - let _ = A.min(B); // Both are constants - let _ = 6_i32.min(9); // Both are Literals + /* + */ + const A: i64 = 45; + const B: i64 = -1; + const C: i64 = const_fn(B); + let _ = (A * B).min(B); // Both are constants + let _ = C.min(B); // Both are constants + let _ = B.min(C); // Both are constants + + let _ = (-6_i32).min(9); // Both are Literals + let _ = 9_u32.min(6); // Both are Literals + + /* let _ = 6.min(7_u8); // Both are Literals let _ = 0.min(7_u8); // unsigned with zero @@ -25,6 +34,7 @@ fn main() { let _ = i64::MAX.min(test_i64()); // signed with MAX and function let _ = test_i64().min(i64::MAX); // signed with MAX and function + */ } fn test_usize() -> usize { 42 @@ -32,3 +42,6 @@ fn test_usize() -> usize { fn test_i64() -> i64 { 42 } +const fn const_fn(input: i64) -> i64 { + -2 * input +} diff --git a/tests/ui/unnecessary_min.stderr b/tests/ui/unnecessary_min.stderr index d3e15693ec83..5d5961bc8803 100644 --- a/tests/ui/unnecessary_min.stderr +++ b/tests/ui/unnecessary_min.stderr @@ -1,29 +1,35 @@ -error: this operation has no effect - --> $DIR/unnecessary_min.rs:11:13 +error: (A * B) is never greater than B and has therefore no effect + --> $DIR/unnecessary_min.rs:10:13 | -LL | let _ = 0.min(7_u8); // unsigned with zero - | ^^^^^^^^^^^ help: try: : `0` +LL | let _ = (A * B).min(B); // Both are constants + | ^^^^^^^^^^^^^^ help: try: `(A * B)` | = note: `-D clippy::unnecessary-min` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_min)]` -error: this operation has no effect +error: B is never greater than C and has therefore no effect + --> $DIR/unnecessary_min.rs:11:13 + | +LL | let _ = C.min(B); // Both are constants + | ^^^^^^^^ help: try: `B` + +error: B is never greater than C and has therefore no effect --> $DIR/unnecessary_min.rs:12:13 | -LL | let _ = 7.min(0_u32); // unsigned with zero - | ^^^^^^^^^^^^ help: try: : `0` +LL | let _ = B.min(C); // Both are constants + | ^^^^^^^^ help: try: `B` -error: this operation has no effect - --> $DIR/unnecessary_min.rs:20:13 +error: (-6_i32) is never greater than 9 and has therefore no effect + --> $DIR/unnecessary_min.rs:14:13 | -LL | let _ = 0.min(test_usize()); // unsigned with zero and function - | ^^^^^^^^^^^^^^^^^^^ help: try: : `0` +LL | let _ = (-6_i32).min(9); // Both are Literals + | ^^^^^^^^^^^^^^^ help: try: `(-6_i32)` -error: this operation has no effect - --> $DIR/unnecessary_min.rs:21:13 +error: 6 is never greater than 9_u32 and has therefore no effect + --> $DIR/unnecessary_min.rs:15:13 | -LL | let _ = test_usize().min(0); // unsigned with zero and function - | ^^^^^^^^^^^^^^^^^^^ help: try: : `0` +LL | let _ = 9_u32.min(6); // Both are Literals + | ^^^^^^^^^^^^ help: try: `6` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors From 20257d05790634d9a9ae1a1a966b0c93edf79906 Mon Sep 17 00:00:00 2001 From: FelixMaetzler Date: Fri, 8 Dec 2023 17:18:45 +0100 Subject: [PATCH 03/53] added support for extrema --- clippy_lints/src/methods/unnecessary_min.rs | 22 ++++++ tests/ui/unnecessary_min.fixed | 33 +++++---- tests/ui/unnecessary_min.rs | 7 +- tests/ui/unnecessary_min.stderr | 80 ++++++++++++++++++++- 4 files changed, 124 insertions(+), 18 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_min.rs b/clippy_lints/src/methods/unnecessary_min.rs index 2205e14cf3bc..0b632784702a 100644 --- a/clippy_lints/src/methods/unnecessary_min.rs +++ b/clippy_lints/src/methods/unnecessary_min.rs @@ -19,6 +19,9 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, _: &'tcx Expr<' if both_are_constant(cx, expr) { return; } + if one_extrema(cx, expr) { + return; + } let (left, right) = extract_both(expr); let ty = cx.typeck_results().expr_ty(expr); @@ -177,3 +180,22 @@ fn both_are_constant<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool } false } +fn one_extrema<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { + //let ty = cx.typeck_results().expr_ty(expr); + let (left, right) = get_both_as_expr(expr); + if let Some(extrema) = detect_extrema(cx, left) { + match extrema { + Extrema::Minimum => lint(cx, expr, left.span, right.span), + Extrema::Maximum => lint(cx, expr, right.span, left.span), + } + return true; + } else if let Some(extrema) = detect_extrema(cx, right) { + match extrema { + Extrema::Minimum => lint(cx, expr, right.span, left.span), + Extrema::Maximum => lint(cx, expr, left.span, right.span), + } + return true; + } + + false +} diff --git a/tests/ui/unnecessary_min.fixed b/tests/ui/unnecessary_min.fixed index 918481c8cb39..1beef7982b2c 100644 --- a/tests/ui/unnecessary_min.fixed +++ b/tests/ui/unnecessary_min.fixed @@ -14,27 +14,30 @@ fn main() { let _ = (-6_i32); // Both are Literals let _ = 6; // Both are Literals - /* - let _ = 6.min(7_u8); // Both are Literals + let _ = 6; // Both are Literals + + let _ = 0; // unsigned with zero + let _ = 0_u32; // unsigned with zero - let _ = 0.min(7_u8); // unsigned with zero - let _ = 7.min(0_u32); // unsigned with zero + let _ = i32::MIN; // singed MIN + let _ = i32::MIN; // singed MIN - let _ = i32::MIN.min(42); // singed MIN - let _ = 42.min(i32::MIN); // singed MIN + let _ = 42; // singed MAX + let _ = 42; // singed MAX - let _ = i32::MAX.min(42); // singed MAX - let _ = 42.min(i32::MAX); // singed MAX + let _ = 0; // unsigned with zero and function - let _ = 0.min(test_usize()); // unsigned with zero and function - let _ = test_usize().min(0); // unsigned with zero and function + let _ = 0; // unsigned with zero and function - let _ = i64::MIN.min(test_i64()); // signed with MIN and function - let _ = test_i64().min(i64::MIN); // signed with MIN and function + let _ = i64::MIN; // signed with MIN and function - let _ = i64::MAX.min(test_i64()); // signed with MAX and function - let _ = test_i64().min(i64::MAX); // signed with MAX and function - */ + let _ = i64::MIN; // signed with MIN and function + + let _ = test_i64(); // signed with MAX and function + let _ = test_i64(); // signed with MAX and function + // + /* + */ } fn test_usize() -> usize { 42 diff --git a/tests/ui/unnecessary_min.rs b/tests/ui/unnecessary_min.rs index cb375470a1c2..e55d2f759095 100644 --- a/tests/ui/unnecessary_min.rs +++ b/tests/ui/unnecessary_min.rs @@ -14,7 +14,6 @@ fn main() { let _ = (-6_i32).min(9); // Both are Literals let _ = 9_u32.min(6); // Both are Literals - /* let _ = 6.min(7_u8); // Both are Literals let _ = 0.min(7_u8); // unsigned with zero @@ -27,14 +26,18 @@ fn main() { let _ = 42.min(i32::MAX); // singed MAX let _ = 0.min(test_usize()); // unsigned with zero and function + let _ = test_usize().min(0); // unsigned with zero and function let _ = i64::MIN.min(test_i64()); // signed with MIN and function + let _ = test_i64().min(i64::MIN); // signed with MIN and function let _ = i64::MAX.min(test_i64()); // signed with MAX and function let _ = test_i64().min(i64::MAX); // signed with MAX and function - */ + // + /* + */ } fn test_usize() -> usize { 42 diff --git a/tests/ui/unnecessary_min.stderr b/tests/ui/unnecessary_min.stderr index 5d5961bc8803..5e8aec0174b5 100644 --- a/tests/ui/unnecessary_min.stderr +++ b/tests/ui/unnecessary_min.stderr @@ -31,5 +31,83 @@ error: 6 is never greater than 9_u32 and has therefore no effect LL | let _ = 9_u32.min(6); // Both are Literals | ^^^^^^^^^^^^ help: try: `6` -error: aborting due to 5 previous errors +error: 6 is never greater than 7_u8 and has therefore no effect + --> $DIR/unnecessary_min.rs:17:13 + | +LL | let _ = 6.min(7_u8); // Both are Literals + | ^^^^^^^^^^^ help: try: `6` + +error: 0 is never greater than 7_u8 and has therefore no effect + --> $DIR/unnecessary_min.rs:19:13 + | +LL | let _ = 0.min(7_u8); // unsigned with zero + | ^^^^^^^^^^^ help: try: `0` + +error: 0_u32 is never greater than 7 and has therefore no effect + --> $DIR/unnecessary_min.rs:20:13 + | +LL | let _ = 7.min(0_u32); // unsigned with zero + | ^^^^^^^^^^^^ help: try: `0_u32` + +error: i32::MIN is never greater than 42 and has therefore no effect + --> $DIR/unnecessary_min.rs:22:13 + | +LL | let _ = i32::MIN.min(42); // singed MIN + | ^^^^^^^^^^^^^^^^ help: try: `i32::MIN` + +error: i32::MIN is never greater than 42 and has therefore no effect + --> $DIR/unnecessary_min.rs:23:13 + | +LL | let _ = 42.min(i32::MIN); // singed MIN + | ^^^^^^^^^^^^^^^^ help: try: `i32::MIN` + +error: 42 is never greater than i32::MAX and has therefore no effect + --> $DIR/unnecessary_min.rs:25:13 + | +LL | let _ = i32::MAX.min(42); // singed MAX + | ^^^^^^^^^^^^^^^^ help: try: `42` + +error: 42 is never greater than i32::MAX and has therefore no effect + --> $DIR/unnecessary_min.rs:26:13 + | +LL | let _ = 42.min(i32::MAX); // singed MAX + | ^^^^^^^^^^^^^^^^ help: try: `42` + +error: 0 is never greater than test_usize() and has therefore no effect + --> $DIR/unnecessary_min.rs:28:13 + | +LL | let _ = 0.min(test_usize()); // unsigned with zero and function + | ^^^^^^^^^^^^^^^^^^^ help: try: `0` + +error: 0 is never greater than test_usize() and has therefore no effect + --> $DIR/unnecessary_min.rs:30:13 + | +LL | let _ = test_usize().min(0); // unsigned with zero and function + | ^^^^^^^^^^^^^^^^^^^ help: try: `0` + +error: i64::MIN is never greater than test_i64() and has therefore no effect + --> $DIR/unnecessary_min.rs:32:13 + | +LL | let _ = i64::MIN.min(test_i64()); // signed with MIN and function + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i64::MIN` + +error: i64::MIN is never greater than test_i64() and has therefore no effect + --> $DIR/unnecessary_min.rs:34:13 + | +LL | let _ = test_i64().min(i64::MIN); // signed with MIN and function + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i64::MIN` + +error: test_i64() is never greater than i64::MAX and has therefore no effect + --> $DIR/unnecessary_min.rs:36:13 + | +LL | let _ = i64::MAX.min(test_i64()); // signed with MAX and function + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `test_i64()` + +error: test_i64() is never greater than i64::MAX and has therefore no effect + --> $DIR/unnecessary_min.rs:37:13 + | +LL | let _ = test_i64().min(i64::MAX); // signed with MAX and function + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `test_i64()` + +error: aborting due to 18 previous errors From e38c7e23c27f90f9f0d44131b998eb0b41832f40 Mon Sep 17 00:00:00 2001 From: FelixMaetzler Date: Mon, 11 Dec 2023 10:50:51 +0100 Subject: [PATCH 04/53] needed to modify other test for cargo test passing --- tests/ui/cast.rs | 7 ++- tests/ui/cast.stderr | 102 +++++++++++++++++++++---------------------- 2 files changed, 57 insertions(+), 52 deletions(-) diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index 1ca18170f8a0..439cb02a38f6 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -8,7 +8,12 @@ clippy::cast_sign_loss, clippy::cast_possible_wrap )] -#![allow(clippy::cast_abs_to_unsigned, clippy::no_effect, clippy::unnecessary_operation)] +#![allow( + clippy::cast_abs_to_unsigned, + clippy::no_effect, + clippy::unnecessary_operation, + clippy::unnecessary_min +)] fn main() { // Test clippy::cast_precision_loss diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index bc74f7b728e8..6e916b446011 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -1,5 +1,5 @@ error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> $DIR/cast.rs:16:5 + --> $DIR/cast.rs:21:5 | LL | x0 as f32; | ^^^^^^^^^ @@ -8,37 +8,37 @@ LL | x0 as f32; = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> $DIR/cast.rs:20:5 + --> $DIR/cast.rs:25:5 | LL | x1 as f32; | ^^^^^^^^^ error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> $DIR/cast.rs:22:5 + --> $DIR/cast.rs:27:5 | LL | x1 as f64; | ^^^^^^^^^ error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> $DIR/cast.rs:25:5 + --> $DIR/cast.rs:30:5 | LL | x2 as f32; | ^^^^^^^^^ error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> $DIR/cast.rs:28:5 + --> $DIR/cast.rs:33:5 | LL | x3 as f32; | ^^^^^^^^^ error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> $DIR/cast.rs:30:5 + --> $DIR/cast.rs:35:5 | LL | x3 as f64; | ^^^^^^^^^ error: casting `f32` to `i32` may truncate the value - --> $DIR/cast.rs:33:5 + --> $DIR/cast.rs:38:5 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | 1f32 as i32; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]` error: casting `f32` to `u32` may truncate the value - --> $DIR/cast.rs:35:5 + --> $DIR/cast.rs:40:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | 1f32 as u32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> $DIR/cast.rs:35:5 + --> $DIR/cast.rs:40:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | 1f32 as u32; = help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]` error: casting `f64` to `f32` may truncate the value - --> $DIR/cast.rs:39:5 + --> $DIR/cast.rs:44:5 | LL | 1f64 as f32; | ^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | 1f64 as f32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `i32` to `i8` may truncate the value - --> $DIR/cast.rs:41:5 + --> $DIR/cast.rs:46:5 | LL | 1i32 as i8; | ^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | i8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `i32` to `u8` may truncate the value - --> $DIR/cast.rs:43:5 + --> $DIR/cast.rs:48:5 | LL | 1i32 as u8; | ^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | u8::try_from(1i32); | ~~~~~~~~~~~~~~~~~~ error: casting `f64` to `isize` may truncate the value - --> $DIR/cast.rs:45:5 + --> $DIR/cast.rs:50:5 | LL | 1f64 as isize; | ^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | 1f64 as isize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may truncate the value - --> $DIR/cast.rs:47:5 + --> $DIR/cast.rs:52:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ @@ -113,13 +113,13 @@ LL | 1f64 as usize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may lose the sign of the value - --> $DIR/cast.rs:47:5 + --> $DIR/cast.rs:52:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting `u32` to `u16` may truncate the value - --> $DIR/cast.rs:50:5 + --> $DIR/cast.rs:55:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | u16::try_from(1f32 as u32); | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `f32` to `u32` may truncate the value - --> $DIR/cast.rs:50:5 + --> $DIR/cast.rs:55:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ @@ -139,13 +139,13 @@ LL | 1f32 as u32 as u16; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> $DIR/cast.rs:50:5 + --> $DIR/cast.rs:55:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ error: casting `i32` to `i8` may truncate the value - --> $DIR/cast.rs:55:22 + --> $DIR/cast.rs:60:22 | LL | let _x: i8 = 1i32 as _; | ^^^^^^^^^ @@ -157,7 +157,7 @@ LL | let _x: i8 = 1i32.try_into(); | ~~~~~~~~~~~~~~~ error: casting `f32` to `i32` may truncate the value - --> $DIR/cast.rs:57:9 + --> $DIR/cast.rs:62:9 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | 1f32 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `i32` may truncate the value - --> $DIR/cast.rs:59:9 + --> $DIR/cast.rs:64:9 | LL | 1f64 as i32; | ^^^^^^^^^^^ @@ -173,7 +173,7 @@ LL | 1f64 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may truncate the value - --> $DIR/cast.rs:61:9 + --> $DIR/cast.rs:66:9 | LL | 1f32 as u8; | ^^^^^^^^^^ @@ -181,13 +181,13 @@ LL | 1f32 as u8; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may lose the sign of the value - --> $DIR/cast.rs:61:9 + --> $DIR/cast.rs:66:9 | LL | 1f32 as u8; | ^^^^^^^^^^ error: casting `u8` to `i8` may wrap around the value - --> $DIR/cast.rs:66:5 + --> $DIR/cast.rs:71:5 | LL | 1u8 as i8; | ^^^^^^^^^ @@ -196,31 +196,31 @@ LL | 1u8 as i8; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` error: casting `u16` to `i16` may wrap around the value - --> $DIR/cast.rs:69:5 + --> $DIR/cast.rs:74:5 | LL | 1u16 as i16; | ^^^^^^^^^^^ error: casting `u32` to `i32` may wrap around the value - --> $DIR/cast.rs:71:5 + --> $DIR/cast.rs:76:5 | LL | 1u32 as i32; | ^^^^^^^^^^^ error: casting `u64` to `i64` may wrap around the value - --> $DIR/cast.rs:73:5 + --> $DIR/cast.rs:78:5 | LL | 1u64 as i64; | ^^^^^^^^^^^ error: casting `usize` to `isize` may wrap around the value - --> $DIR/cast.rs:75:5 + --> $DIR/cast.rs:80:5 | LL | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting `usize` to `i8` may truncate the value - --> $DIR/cast.rs:78:5 + --> $DIR/cast.rs:83:5 | LL | 1usize as i8; | ^^^^^^^^^^^^ @@ -232,7 +232,7 @@ LL | i8::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may truncate the value - --> $DIR/cast.rs:81:5 + --> $DIR/cast.rs:86:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -244,7 +244,7 @@ LL | i16::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers - --> $DIR/cast.rs:81:5 + --> $DIR/cast.rs:86:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -253,7 +253,7 @@ LL | 1usize as i16; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> $DIR/cast.rs:86:5 + --> $DIR/cast.rs:91:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -265,19 +265,19 @@ LL | i32::try_from(1usize); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers - --> $DIR/cast.rs:86:5 + --> $DIR/cast.rs:91:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers - --> $DIR/cast.rs:90:5 + --> $DIR/cast.rs:95:5 | LL | 1usize as i64; | ^^^^^^^^^^^^^ error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers - --> $DIR/cast.rs:95:5 + --> $DIR/cast.rs:100:5 | LL | 1u16 as isize; | ^^^^^^^^^^^^^ @@ -286,13 +286,13 @@ LL | 1u16 as isize; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers - --> $DIR/cast.rs:99:5 + --> $DIR/cast.rs:104:5 | LL | 1u32 as isize; | ^^^^^^^^^^^^^ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> $DIR/cast.rs:102:5 + --> $DIR/cast.rs:107:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ @@ -304,25 +304,25 @@ LL | isize::try_from(1u64); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers - --> $DIR/cast.rs:102:5 + --> $DIR/cast.rs:107:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> $DIR/cast.rs:107:5 + --> $DIR/cast.rs:112:5 | LL | -1i32 as u32; | ^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> $DIR/cast.rs:110:5 + --> $DIR/cast.rs:115:5 | LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ error: casting `i64` to `i8` may truncate the value - --> $DIR/cast.rs:179:5 + --> $DIR/cast.rs:184:5 | LL | (-99999999999i64).min(1) as i8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -334,7 +334,7 @@ LL | i8::try_from((-99999999999i64).min(1)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> $DIR/cast.rs:193:5 + --> $DIR/cast.rs:198:5 | LL | 999999u64.clamp(0, 256) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -346,7 +346,7 @@ LL | u8::try_from(999999u64.clamp(0, 256)); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E2` to `u8` may truncate the value - --> $DIR/cast.rs:216:21 + --> $DIR/cast.rs:221:21 | LL | let _ = self as u8; | ^^^^^^^^^^ @@ -358,7 +358,7 @@ LL | let _ = u8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E2::B` to `u8` will truncate the value - --> $DIR/cast.rs:218:21 + --> $DIR/cast.rs:223:21 | LL | let _ = Self::B as u8; | ^^^^^^^^^^^^^ @@ -367,7 +367,7 @@ LL | let _ = Self::B as u8; = help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]` error: casting `main::E5` to `i8` may truncate the value - --> $DIR/cast.rs:260:21 + --> $DIR/cast.rs:265:21 | LL | let _ = self as i8; | ^^^^^^^^^^ @@ -379,13 +379,13 @@ LL | let _ = i8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E5::A` to `i8` will truncate the value - --> $DIR/cast.rs:262:21 + --> $DIR/cast.rs:267:21 | LL | let _ = Self::A as i8; | ^^^^^^^^^^^^^ error: casting `main::E6` to `i16` may truncate the value - --> $DIR/cast.rs:279:21 + --> $DIR/cast.rs:284:21 | LL | let _ = self as i16; | ^^^^^^^^^^^ @@ -397,7 +397,7 @@ LL | let _ = i16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers - --> $DIR/cast.rs:298:21 + --> $DIR/cast.rs:303:21 | LL | let _ = self as usize; | ^^^^^^^^^^^^^ @@ -409,7 +409,7 @@ LL | let _ = usize::try_from(self); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E10` to `u16` may truncate the value - --> $DIR/cast.rs:345:21 + --> $DIR/cast.rs:350:21 | LL | let _ = self as u16; | ^^^^^^^^^^^ @@ -421,7 +421,7 @@ LL | let _ = u16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> $DIR/cast.rs:356:13 + --> $DIR/cast.rs:361:13 | LL | let c = (q >> 16) as u8; | ^^^^^^^^^^^^^^^ @@ -433,7 +433,7 @@ LL | let c = u8::try_from(q >> 16); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> $DIR/cast.rs:360:13 + --> $DIR/cast.rs:365:13 | LL | let c = (q / 1000) as u8; | ^^^^^^^^^^^^^^^^ From 923d964727ff001f2effa22e196b211debc425dd Mon Sep 17 00:00:00 2001 From: FelixMaetzler Date: Mon, 11 Dec 2023 11:05:06 +0100 Subject: [PATCH 05/53] made cargo test happy --- clippy_lints/src/methods/unnecessary_min.rs | 17 ++++------ tests/ui/unnecessary_min.stderr | 36 ++++++++++----------- 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_min.rs b/clippy_lints/src/methods/unnecessary_min.rs index 0b632784702a..c1de3eb4cd3c 100644 --- a/clippy_lints/src/methods/unnecessary_min.rs +++ b/clippy_lints/src/methods/unnecessary_min.rs @@ -22,10 +22,9 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, _: &'tcx Expr<' if one_extrema(cx, expr) { return; } + let (left, right) = extract_both(expr); let ty = cx.typeck_results().expr_ty(expr); - - //------- if !matches!(ty.kind(), ty::Uint(_)) { return; } @@ -57,9 +56,9 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, _: &'tcx Expr<' } } } -fn lint<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>, sugg: Span, other: Span) { +fn lint(cx: &LateContext<'_>, expr: &Expr<'_>, sugg: Span, other: Span) { let msg = format!( - "{} is never greater than {} and has therefore no effect", + "`{}` is never greater than `{}` and has therefore no effect", snippet(cx, sugg, "Not yet implemented"), snippet(cx, other, "Not yet implemented") ); @@ -79,7 +78,7 @@ fn extract_both<'tcx>(expr: &'tcx Expr<'_>) -> (ExprKind<'tcx>, ExprKind<'tcx>) hir::ExprKind::MethodCall(_, left1, right1, _) => { let left = left1.kind; let right = right1[0].kind; - return (left, right); + (left, right) }, _ => unreachable!("this function gets only called on methods"), } @@ -97,7 +96,7 @@ fn get_both_as_expr<'tcx>(expr: &'tcx Expr<'_>) -> (&'tcx Expr<'tcx>, &'tcx Expr hir::ExprKind::MethodCall(_, left1, right1, _) => { let left = left1; let right = &right1[0]; - return (left, right); + (left, right) }, _ => unreachable!("this function gets only called on methods"), } @@ -135,10 +134,9 @@ fn cmp_for_signed(a: u128, b: u128, cx: &LateContext<'_>, ty: IntTy) -> Ordering // iX::MAX b0111... // 0 b0000... uX::MIN match (a_sign, b_sign) { - (Sign::Positive, Sign::Positive) => a.cmp(&b), + (Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => a.cmp(&b), (Sign::Positive, Sign::Negative) => Ordering::Greater, (Sign::Negative, Sign::Positive) => Ordering::Less, - (Sign::Negative, Sign::Negative) => a.cmp(&b), } } #[derive(Debug)] @@ -171,8 +169,7 @@ fn both_are_constant<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool let (sugg, other) = match ord { Ordering::Less => (get_both_as_expr(expr).0.span, get_both_as_expr(expr).1.span), - Ordering::Equal => (get_both_as_expr(expr).1.span, get_both_as_expr(expr).0.span), - Ordering::Greater => (get_both_as_expr(expr).1.span, get_both_as_expr(expr).0.span), + Ordering::Equal | Ordering::Greater => (get_both_as_expr(expr).1.span, get_both_as_expr(expr).0.span), }; lint(cx, expr, sugg, other); diff --git a/tests/ui/unnecessary_min.stderr b/tests/ui/unnecessary_min.stderr index 5e8aec0174b5..2a016ef833cb 100644 --- a/tests/ui/unnecessary_min.stderr +++ b/tests/ui/unnecessary_min.stderr @@ -1,4 +1,4 @@ -error: (A * B) is never greater than B and has therefore no effect +error: `(A * B)` is never greater than `B` and has therefore no effect --> $DIR/unnecessary_min.rs:10:13 | LL | let _ = (A * B).min(B); // Both are constants @@ -7,103 +7,103 @@ LL | let _ = (A * B).min(B); // Both are constants = note: `-D clippy::unnecessary-min` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_min)]` -error: B is never greater than C and has therefore no effect +error: `B` is never greater than `C` and has therefore no effect --> $DIR/unnecessary_min.rs:11:13 | LL | let _ = C.min(B); // Both are constants | ^^^^^^^^ help: try: `B` -error: B is never greater than C and has therefore no effect +error: `B` is never greater than `C` and has therefore no effect --> $DIR/unnecessary_min.rs:12:13 | LL | let _ = B.min(C); // Both are constants | ^^^^^^^^ help: try: `B` -error: (-6_i32) is never greater than 9 and has therefore no effect +error: `(-6_i32)` is never greater than `9` and has therefore no effect --> $DIR/unnecessary_min.rs:14:13 | LL | let _ = (-6_i32).min(9); // Both are Literals | ^^^^^^^^^^^^^^^ help: try: `(-6_i32)` -error: 6 is never greater than 9_u32 and has therefore no effect +error: `6` is never greater than `9_u32` and has therefore no effect --> $DIR/unnecessary_min.rs:15:13 | LL | let _ = 9_u32.min(6); // Both are Literals | ^^^^^^^^^^^^ help: try: `6` -error: 6 is never greater than 7_u8 and has therefore no effect +error: `6` is never greater than `7_u8` and has therefore no effect --> $DIR/unnecessary_min.rs:17:13 | LL | let _ = 6.min(7_u8); // Both are Literals | ^^^^^^^^^^^ help: try: `6` -error: 0 is never greater than 7_u8 and has therefore no effect +error: `0` is never greater than `7_u8` and has therefore no effect --> $DIR/unnecessary_min.rs:19:13 | LL | let _ = 0.min(7_u8); // unsigned with zero | ^^^^^^^^^^^ help: try: `0` -error: 0_u32 is never greater than 7 and has therefore no effect +error: `0_u32` is never greater than `7` and has therefore no effect --> $DIR/unnecessary_min.rs:20:13 | LL | let _ = 7.min(0_u32); // unsigned with zero | ^^^^^^^^^^^^ help: try: `0_u32` -error: i32::MIN is never greater than 42 and has therefore no effect +error: `i32::MIN` is never greater than `42` and has therefore no effect --> $DIR/unnecessary_min.rs:22:13 | LL | let _ = i32::MIN.min(42); // singed MIN | ^^^^^^^^^^^^^^^^ help: try: `i32::MIN` -error: i32::MIN is never greater than 42 and has therefore no effect +error: `i32::MIN` is never greater than `42` and has therefore no effect --> $DIR/unnecessary_min.rs:23:13 | LL | let _ = 42.min(i32::MIN); // singed MIN | ^^^^^^^^^^^^^^^^ help: try: `i32::MIN` -error: 42 is never greater than i32::MAX and has therefore no effect +error: `42` is never greater than `i32::MAX` and has therefore no effect --> $DIR/unnecessary_min.rs:25:13 | LL | let _ = i32::MAX.min(42); // singed MAX | ^^^^^^^^^^^^^^^^ help: try: `42` -error: 42 is never greater than i32::MAX and has therefore no effect +error: `42` is never greater than `i32::MAX` and has therefore no effect --> $DIR/unnecessary_min.rs:26:13 | LL | let _ = 42.min(i32::MAX); // singed MAX | ^^^^^^^^^^^^^^^^ help: try: `42` -error: 0 is never greater than test_usize() and has therefore no effect +error: `0` is never greater than `test_usize()` and has therefore no effect --> $DIR/unnecessary_min.rs:28:13 | LL | let _ = 0.min(test_usize()); // unsigned with zero and function | ^^^^^^^^^^^^^^^^^^^ help: try: `0` -error: 0 is never greater than test_usize() and has therefore no effect +error: `0` is never greater than `test_usize()` and has therefore no effect --> $DIR/unnecessary_min.rs:30:13 | LL | let _ = test_usize().min(0); // unsigned with zero and function | ^^^^^^^^^^^^^^^^^^^ help: try: `0` -error: i64::MIN is never greater than test_i64() and has therefore no effect +error: `i64::MIN` is never greater than `test_i64()` and has therefore no effect --> $DIR/unnecessary_min.rs:32:13 | LL | let _ = i64::MIN.min(test_i64()); // signed with MIN and function | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i64::MIN` -error: i64::MIN is never greater than test_i64() and has therefore no effect +error: `i64::MIN` is never greater than `test_i64()` and has therefore no effect --> $DIR/unnecessary_min.rs:34:13 | LL | let _ = test_i64().min(i64::MIN); // signed with MIN and function | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i64::MIN` -error: test_i64() is never greater than i64::MAX and has therefore no effect +error: `test_i64()` is never greater than `i64::MAX` and has therefore no effect --> $DIR/unnecessary_min.rs:36:13 | LL | let _ = i64::MAX.min(test_i64()); // signed with MAX and function | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `test_i64()` -error: test_i64() is never greater than i64::MAX and has therefore no effect +error: `test_i64()` is never greater than `i64::MAX` and has therefore no effect --> $DIR/unnecessary_min.rs:37:13 | LL | let _ = test_i64().min(i64::MAX); // signed with MAX and function From b376f4656cf3829572e6ebd70a0d15f4d9165f92 Mon Sep 17 00:00:00 2001 From: FelixMaetzler Date: Mon, 11 Dec 2023 11:10:16 +0100 Subject: [PATCH 06/53] removed redundant code --- clippy_lints/src/methods/unnecessary_min.rs | 54 ++------------------- 1 file changed, 4 insertions(+), 50 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_min.rs b/clippy_lints/src/methods/unnecessary_min.rs index c1de3eb4cd3c..69dcd480f6fb 100644 --- a/clippy_lints/src/methods/unnecessary_min.rs +++ b/clippy_lints/src/methods/unnecessary_min.rs @@ -6,8 +6,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::consts::{constant, Constant}; use clippy_utils::source::snippet; use clippy_utils::{clip, int_bits, unsext}; -use hir::{Expr, ExprKind}; -use rustc_ast::LitKind; +use hir::Expr; + use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -19,42 +19,7 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, _: &'tcx Expr<' if both_are_constant(cx, expr) { return; } - if one_extrema(cx, expr) { - return; - } - - let (left, right) = extract_both(expr); - let ty = cx.typeck_results().expr_ty(expr); - if !matches!(ty.kind(), ty::Uint(_)) { - return; - } - if let ExprKind::Lit(test) = left { - if let LitKind::Int(0, _) = test.node { - span_lint_and_sugg( - cx, - UNNECESSARY_MIN, - expr.span, - "this operation has no effect", - "try: ", - "0".to_string(), - Applicability::MachineApplicable, - ); - } - } - - if let ExprKind::Lit(test) = right { - if let LitKind::Int(0, _) = test.node { - span_lint_and_sugg( - cx, - UNNECESSARY_MIN, - expr.span, - "this operation has no effect", - "try: ", - "0".to_string(), - Applicability::MachineApplicable, - ); - } - } + one_extrema(cx, expr); } fn lint(cx: &LateContext<'_>, expr: &Expr<'_>, sugg: Span, other: Span) { let msg = format!( @@ -73,19 +38,8 @@ fn lint(cx: &LateContext<'_>, expr: &Expr<'_>, sugg: Span, other: Span) { ); } -fn extract_both<'tcx>(expr: &'tcx Expr<'_>) -> (ExprKind<'tcx>, ExprKind<'tcx>) { - match expr.kind { - hir::ExprKind::MethodCall(_, left1, right1, _) => { - let left = left1.kind; - let right = right1[0].kind; - (left, right) - }, - _ => unreachable!("this function gets only called on methods"), - } -} fn try_to_eval<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> (Option>, Option>) { let (left, right) = get_both_as_expr(expr); - ( (constant(cx, cx.typeck_results(), left)), (constant(cx, cx.typeck_results(), right)), @@ -128,7 +82,7 @@ fn detect_extrema<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option< fn cmp_for_signed(a: u128, b: u128, cx: &LateContext<'_>, ty: IntTy) -> Ordering { let a_sign = Sign::from((a, cx, ty)); let b_sign = Sign::from((b, cx, ty)); - // The Ordering of a signed integer interpreted as a unsigned is as follows: + // The Ordering of a signed integer interpreted as a unsigned integer is as follows: // -1 b1111... uX::MAX // iX::MIN b1000... // iX::MAX b0111... From 6136434b8b62337b6493f8733f4043d232b45254 Mon Sep 17 00:00:00 2001 From: FelixMaetzler Date: Mon, 11 Dec 2023 11:21:11 +0100 Subject: [PATCH 07/53] added description of lint --- clippy_lints/src/methods/mod.rs | 8 +++----- clippy_lints/src/methods/unnecessary_min.rs | 5 +++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 85269056de25..88bce98a8c1e 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3755,25 +3755,23 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for unnecessary calls to min() + /// Checks for unnecessary calls to `min()` /// /// ### Why is this bad? /// - /// In these cases it is not necessary to call min() + /// In these cases it is not necessary to call `min()` /// ### Example /// ```no_run - /// // example code where clippy issues a warning /// let _ = 0.min(7_u32); /// ``` /// Use instead: /// ```no_run - /// // example code which does not raise clippy warning /// let _ = 7; /// ``` #[clippy::version = "1.76.0"] pub UNNECESSARY_MIN, complexity, - "default lint description" + "using 'min()' when there is no need for it" } pub struct Methods { diff --git a/clippy_lints/src/methods/unnecessary_min.rs b/clippy_lints/src/methods/unnecessary_min.rs index 69dcd480f6fb..59b47b4008f2 100644 --- a/clippy_lints/src/methods/unnecessary_min.rs +++ b/clippy_lints/src/methods/unnecessary_min.rs @@ -100,12 +100,13 @@ enum Sign { } impl From<(u128, &LateContext<'_>, IntTy)> for Sign { fn from(value: (u128, &LateContext<'_>, IntTy)) -> Self { - // The MSB decides wether the value has a negative sign in front of it or not + // The MSB decides whether the value has a negative sign in front of it or not // the value 0 is counting as positive (or as non-negative) let (value, cx, ity) = value; // shifting the MSB from a iX (i32, i64, etc) to the MSB from a i128 let value = value << (128 - int_bits(cx.tcx, ity)); - match (value.reverse_bits()) & 1_u128 { + let msb = (value.reverse_bits()) & 1_u128; // single out the MSB + match msb { 0 => Self::Positive, 1 => Self::Negative, _ => unreachable!("Bit can only be 0 or 1"), From 8d9d196b4cbe297de8a0bdb943c3e8eec2719dd3 Mon Sep 17 00:00:00 2001 From: Felix <72246508+FelixMaetzler@users.noreply.github.com> Date: Wed, 13 Dec 2023 15:55:10 +0100 Subject: [PATCH 08/53] remove useless comments Co-authored-by: Marti Raudsepp --- tests/ui/unnecessary_min.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/ui/unnecessary_min.rs b/tests/ui/unnecessary_min.rs index e55d2f759095..e2f0079f9d86 100644 --- a/tests/ui/unnecessary_min.rs +++ b/tests/ui/unnecessary_min.rs @@ -35,9 +35,6 @@ fn main() { let _ = i64::MAX.min(test_i64()); // signed with MAX and function let _ = test_i64().min(i64::MAX); // signed with MAX and function - // - /* - */ } fn test_usize() -> usize { 42 From 072a07786f69e0cb4285405f64f8d49f0bb76422 Mon Sep 17 00:00:00 2001 From: Felix <72246508+FelixMaetzler@users.noreply.github.com> Date: Wed, 13 Dec 2023 15:55:28 +0100 Subject: [PATCH 09/53] remove useless comments Co-authored-by: Marti Raudsepp --- tests/ui/unnecessary_min.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/ui/unnecessary_min.rs b/tests/ui/unnecessary_min.rs index e2f0079f9d86..8c6e50fd04b7 100644 --- a/tests/ui/unnecessary_min.rs +++ b/tests/ui/unnecessary_min.rs @@ -2,8 +2,6 @@ #![warn(clippy::unnecessary_min)] fn main() { - /* - */ const A: i64 = 45; const B: i64 = -1; const C: i64 = const_fn(B); From 7a32e989ee7b144168b7fff34dc096b092d59daa Mon Sep 17 00:00:00 2001 From: FelixMaetzler Date: Wed, 13 Dec 2023 16:19:35 +0100 Subject: [PATCH 10/53] modified the test files bc of last commit --- tests/ui/unnecessary_min.fixed | 5 ----- tests/ui/unnecessary_min.stderr | 36 ++++++++++++++++----------------- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/tests/ui/unnecessary_min.fixed b/tests/ui/unnecessary_min.fixed index 1beef7982b2c..a81f1dabc481 100644 --- a/tests/ui/unnecessary_min.fixed +++ b/tests/ui/unnecessary_min.fixed @@ -2,8 +2,6 @@ #![warn(clippy::unnecessary_min)] fn main() { - /* - */ const A: i64 = 45; const B: i64 = -1; const C: i64 = const_fn(B); @@ -35,9 +33,6 @@ fn main() { let _ = test_i64(); // signed with MAX and function let _ = test_i64(); // signed with MAX and function - // - /* - */ } fn test_usize() -> usize { 42 diff --git a/tests/ui/unnecessary_min.stderr b/tests/ui/unnecessary_min.stderr index 2a016ef833cb..610f34416c25 100644 --- a/tests/ui/unnecessary_min.stderr +++ b/tests/ui/unnecessary_min.stderr @@ -1,5 +1,5 @@ error: `(A * B)` is never greater than `B` and has therefore no effect - --> $DIR/unnecessary_min.rs:10:13 + --> $DIR/unnecessary_min.rs:8:13 | LL | let _ = (A * B).min(B); // Both are constants | ^^^^^^^^^^^^^^ help: try: `(A * B)` @@ -8,103 +8,103 @@ LL | let _ = (A * B).min(B); // Both are constants = help: to override `-D warnings` add `#[allow(clippy::unnecessary_min)]` error: `B` is never greater than `C` and has therefore no effect - --> $DIR/unnecessary_min.rs:11:13 + --> $DIR/unnecessary_min.rs:9:13 | LL | let _ = C.min(B); // Both are constants | ^^^^^^^^ help: try: `B` error: `B` is never greater than `C` and has therefore no effect - --> $DIR/unnecessary_min.rs:12:13 + --> $DIR/unnecessary_min.rs:10:13 | LL | let _ = B.min(C); // Both are constants | ^^^^^^^^ help: try: `B` error: `(-6_i32)` is never greater than `9` and has therefore no effect - --> $DIR/unnecessary_min.rs:14:13 + --> $DIR/unnecessary_min.rs:12:13 | LL | let _ = (-6_i32).min(9); // Both are Literals | ^^^^^^^^^^^^^^^ help: try: `(-6_i32)` error: `6` is never greater than `9_u32` and has therefore no effect - --> $DIR/unnecessary_min.rs:15:13 + --> $DIR/unnecessary_min.rs:13:13 | LL | let _ = 9_u32.min(6); // Both are Literals | ^^^^^^^^^^^^ help: try: `6` error: `6` is never greater than `7_u8` and has therefore no effect - --> $DIR/unnecessary_min.rs:17:13 + --> $DIR/unnecessary_min.rs:15:13 | LL | let _ = 6.min(7_u8); // Both are Literals | ^^^^^^^^^^^ help: try: `6` error: `0` is never greater than `7_u8` and has therefore no effect - --> $DIR/unnecessary_min.rs:19:13 + --> $DIR/unnecessary_min.rs:17:13 | LL | let _ = 0.min(7_u8); // unsigned with zero | ^^^^^^^^^^^ help: try: `0` error: `0_u32` is never greater than `7` and has therefore no effect - --> $DIR/unnecessary_min.rs:20:13 + --> $DIR/unnecessary_min.rs:18:13 | LL | let _ = 7.min(0_u32); // unsigned with zero | ^^^^^^^^^^^^ help: try: `0_u32` error: `i32::MIN` is never greater than `42` and has therefore no effect - --> $DIR/unnecessary_min.rs:22:13 + --> $DIR/unnecessary_min.rs:20:13 | LL | let _ = i32::MIN.min(42); // singed MIN | ^^^^^^^^^^^^^^^^ help: try: `i32::MIN` error: `i32::MIN` is never greater than `42` and has therefore no effect - --> $DIR/unnecessary_min.rs:23:13 + --> $DIR/unnecessary_min.rs:21:13 | LL | let _ = 42.min(i32::MIN); // singed MIN | ^^^^^^^^^^^^^^^^ help: try: `i32::MIN` error: `42` is never greater than `i32::MAX` and has therefore no effect - --> $DIR/unnecessary_min.rs:25:13 + --> $DIR/unnecessary_min.rs:23:13 | LL | let _ = i32::MAX.min(42); // singed MAX | ^^^^^^^^^^^^^^^^ help: try: `42` error: `42` is never greater than `i32::MAX` and has therefore no effect - --> $DIR/unnecessary_min.rs:26:13 + --> $DIR/unnecessary_min.rs:24:13 | LL | let _ = 42.min(i32::MAX); // singed MAX | ^^^^^^^^^^^^^^^^ help: try: `42` error: `0` is never greater than `test_usize()` and has therefore no effect - --> $DIR/unnecessary_min.rs:28:13 + --> $DIR/unnecessary_min.rs:26:13 | LL | let _ = 0.min(test_usize()); // unsigned with zero and function | ^^^^^^^^^^^^^^^^^^^ help: try: `0` error: `0` is never greater than `test_usize()` and has therefore no effect - --> $DIR/unnecessary_min.rs:30:13 + --> $DIR/unnecessary_min.rs:28:13 | LL | let _ = test_usize().min(0); // unsigned with zero and function | ^^^^^^^^^^^^^^^^^^^ help: try: `0` error: `i64::MIN` is never greater than `test_i64()` and has therefore no effect - --> $DIR/unnecessary_min.rs:32:13 + --> $DIR/unnecessary_min.rs:30:13 | LL | let _ = i64::MIN.min(test_i64()); // signed with MIN and function | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i64::MIN` error: `i64::MIN` is never greater than `test_i64()` and has therefore no effect - --> $DIR/unnecessary_min.rs:34:13 + --> $DIR/unnecessary_min.rs:32:13 | LL | let _ = test_i64().min(i64::MIN); // signed with MIN and function | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i64::MIN` error: `test_i64()` is never greater than `i64::MAX` and has therefore no effect - --> $DIR/unnecessary_min.rs:36:13 + --> $DIR/unnecessary_min.rs:34:13 | LL | let _ = i64::MAX.min(test_i64()); // signed with MAX and function | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `test_i64()` error: `test_i64()` is never greater than `i64::MAX` and has therefore no effect - --> $DIR/unnecessary_min.rs:37:13 + --> $DIR/unnecessary_min.rs:35:13 | LL | let _ = test_i64().min(i64::MAX); // signed with MAX and function | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `test_i64()` From 2d366177a88a52e705f409e0f802d348c7d3542d Mon Sep 17 00:00:00 2001 From: FelixMaetzler Date: Fri, 15 Dec 2023 13:04:48 +0100 Subject: [PATCH 11/53] got rid of get_both_as_expr --- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/methods/unnecessary_min.rs | 58 ++++++++++----------- 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 88bce98a8c1e..7218f5b116bf 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4207,7 +4207,7 @@ impl Methods { Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2), _ => {}, }, - ("min", [arg]) => unnecessary_min::check(cx, expr, arg), + ("min", [arg]) => unnecessary_min::check(cx, expr, recv, arg), ("drain", ..) => { if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.hir().get_parent(expr.hir_id) && matches!(kind, StmtKind::Semi(_)) diff --git a/clippy_lints/src/methods/unnecessary_min.rs b/clippy_lints/src/methods/unnecessary_min.rs index 59b47b4008f2..b31520fbd996 100644 --- a/clippy_lints/src/methods/unnecessary_min.rs +++ b/clippy_lints/src/methods/unnecessary_min.rs @@ -15,11 +15,11 @@ use rustc_lint::LateContext; use rustc_middle::ty::{self, IntTy}; use rustc_span::Span; -pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, _: &'tcx Expr<'_>) { - if both_are_constant(cx, expr) { +pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) { + if both_are_constant(cx, expr, recv, arg) { return; } - one_extrema(cx, expr); + one_extrema(cx, expr, recv, arg); } fn lint(cx: &LateContext<'_>, expr: &Expr<'_>, sugg: Span, other: Span) { let msg = format!( @@ -38,23 +38,16 @@ fn lint(cx: &LateContext<'_>, expr: &Expr<'_>, sugg: Span, other: Span) { ); } -fn try_to_eval<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> (Option>, Option>) { - let (left, right) = get_both_as_expr(expr); +fn try_to_eval<'tcx>( + cx: &LateContext<'tcx>, + recv: &'tcx Expr<'_>, + arg: &'tcx Expr<'_>, +) -> (Option>, Option>) { ( - (constant(cx, cx.typeck_results(), left)), - (constant(cx, cx.typeck_results(), right)), + (constant(cx, cx.typeck_results(), recv)), + (constant(cx, cx.typeck_results(), arg)), ) } -fn get_both_as_expr<'tcx>(expr: &'tcx Expr<'_>) -> (&'tcx Expr<'tcx>, &'tcx Expr<'tcx>) { - match expr.kind { - hir::ExprKind::MethodCall(_, left1, right1, _) => { - let left = left1; - let right = &right1[0]; - (left, right) - }, - _ => unreachable!("this function gets only called on methods"), - } -} #[derive(Debug)] enum Extrema { Minimum, @@ -113,9 +106,14 @@ impl From<(u128, &LateContext<'_>, IntTy)> for Sign { } } } -fn both_are_constant<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { - let ty = cx.typeck_results().expr_ty(expr); - if let (Some(left), Some(right)) = try_to_eval(cx, expr) { +fn both_are_constant<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + recv: &'tcx Expr<'_>, + arg: &'tcx Expr<'_>, +) -> bool { + let ty = cx.typeck_results().expr_ty(recv); + if let (Some(left), Some(right)) = try_to_eval(cx, recv, arg) { let ord = match (ty.kind(), left, right) { (ty::Int(ty), Constant::Int(left), Constant::Int(right)) => cmp_for_signed(left, right, cx, *ty), (ty::Uint(_), Constant::Int(left), Constant::Int(right)) => left.cmp(&right), @@ -123,8 +121,8 @@ fn both_are_constant<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool }; let (sugg, other) = match ord { - Ordering::Less => (get_both_as_expr(expr).0.span, get_both_as_expr(expr).1.span), - Ordering::Equal | Ordering::Greater => (get_both_as_expr(expr).1.span, get_both_as_expr(expr).0.span), + Ordering::Less => (recv.span, arg.span), + Ordering::Equal | Ordering::Greater => (arg.span, recv.span), }; lint(cx, expr, sugg, other); @@ -132,19 +130,17 @@ fn both_are_constant<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool } false } -fn one_extrema<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { - //let ty = cx.typeck_results().expr_ty(expr); - let (left, right) = get_both_as_expr(expr); - if let Some(extrema) = detect_extrema(cx, left) { +fn one_extrema<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) -> bool { + if let Some(extrema) = detect_extrema(cx, recv) { match extrema { - Extrema::Minimum => lint(cx, expr, left.span, right.span), - Extrema::Maximum => lint(cx, expr, right.span, left.span), + Extrema::Minimum => lint(cx, expr, recv.span, arg.span), + Extrema::Maximum => lint(cx, expr, arg.span, recv.span), } return true; - } else if let Some(extrema) = detect_extrema(cx, right) { + } else if let Some(extrema) = detect_extrema(cx, arg) { match extrema { - Extrema::Minimum => lint(cx, expr, right.span, left.span), - Extrema::Maximum => lint(cx, expr, left.span, right.span), + Extrema::Minimum => lint(cx, expr, arg.span, recv.span), + Extrema::Maximum => lint(cx, expr, recv.span, arg.span), } return true; } From d1a10bf942662cf4bdd6b482d91aadf986e12696 Mon Sep 17 00:00:00 2001 From: FelixMaetzler Date: Fri, 15 Dec 2023 13:14:33 +0100 Subject: [PATCH 12/53] used preexisting cmp method --- clippy_lints/src/methods/unnecessary_min.rs | 46 ++------------------- 1 file changed, 4 insertions(+), 42 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_min.rs b/clippy_lints/src/methods/unnecessary_min.rs index b31520fbd996..5a9593e7d592 100644 --- a/clippy_lints/src/methods/unnecessary_min.rs +++ b/clippy_lints/src/methods/unnecessary_min.rs @@ -12,7 +12,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_middle::ty::{self, IntTy}; +use rustc_middle::ty; use rustc_span::Span; pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) { @@ -72,40 +72,6 @@ fn detect_extrema<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option< _ => None, } } -fn cmp_for_signed(a: u128, b: u128, cx: &LateContext<'_>, ty: IntTy) -> Ordering { - let a_sign = Sign::from((a, cx, ty)); - let b_sign = Sign::from((b, cx, ty)); - // The Ordering of a signed integer interpreted as a unsigned integer is as follows: - // -1 b1111... uX::MAX - // iX::MIN b1000... - // iX::MAX b0111... - // 0 b0000... uX::MIN - match (a_sign, b_sign) { - (Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => a.cmp(&b), - (Sign::Positive, Sign::Negative) => Ordering::Greater, - (Sign::Negative, Sign::Positive) => Ordering::Less, - } -} -#[derive(Debug)] -enum Sign { - Positive, - Negative, -} -impl From<(u128, &LateContext<'_>, IntTy)> for Sign { - fn from(value: (u128, &LateContext<'_>, IntTy)) -> Self { - // The MSB decides whether the value has a negative sign in front of it or not - // the value 0 is counting as positive (or as non-negative) - let (value, cx, ity) = value; - // shifting the MSB from a iX (i32, i64, etc) to the MSB from a i128 - let value = value << (128 - int_bits(cx.tcx, ity)); - let msb = (value.reverse_bits()) & 1_u128; // single out the MSB - match msb { - 0 => Self::Positive, - 1 => Self::Negative, - _ => unreachable!("Bit can only be 0 or 1"), - } - } -} fn both_are_constant<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, @@ -113,13 +79,9 @@ fn both_are_constant<'tcx>( arg: &'tcx Expr<'_>, ) -> bool { let ty = cx.typeck_results().expr_ty(recv); - if let (Some(left), Some(right)) = try_to_eval(cx, recv, arg) { - let ord = match (ty.kind(), left, right) { - (ty::Int(ty), Constant::Int(left), Constant::Int(right)) => cmp_for_signed(left, right, cx, *ty), - (ty::Uint(_), Constant::Int(left), Constant::Int(right)) => left.cmp(&right), - _ => return false, - }; - + if let (Some(left), Some(right)) = try_to_eval(cx, recv, arg) + && let Some(ord) = Constant::partial_cmp(cx.tcx, ty, &left, &right) + { let (sugg, other) = match ord { Ordering::Less => (recv.span, arg.span), Ordering::Equal | Ordering::Greater => (arg.span, recv.span), From 768a615db2ed4a8ecf67e5598d19c13bd418bfe4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 28 Nov 2023 00:59:51 +0000 Subject: [PATCH 13/53] Appease the tools: clippy, rustdoc --- clippy_lints/src/len_zero.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 83af551fcd3c..8c032b170236 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -8,8 +8,8 @@ use rustc_hir::def::Res; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::{ AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind, - ImplicitSelfKind, Item, ItemKind, LangItem, Mutability, Node, PatKind, PathSegment, PrimTy, QPath, TraitItemRef, - TyKind, TypeBindingKind, + ImplicitSelfKind, Item, ItemKind, Mutability, Node, PatKind, PathSegment, PrimTy, QPath, TraitItemRef, + TyKind, TypeBindingKind, OpaqueTyOrigin, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, AssocKind, FnSig, Ty}; @@ -289,8 +289,10 @@ fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<& kind: ItemKind::OpaqueTy(opaque), .. } = item - && opaque.bounds.len() == 1 - && let GenericBound::LangItemTrait(LangItem::Future, _, _, generic_args) = &opaque.bounds[0] + && let OpaqueTyOrigin::AsyncFn(_) = opaque.origin + && let [GenericBound::Trait(trait_ref, _)] = &opaque.bounds + && let Some(segment) = trait_ref.trait_ref.path.segments.last() + && let Some(generic_args) = segment.args && generic_args.bindings.len() == 1 && let TypeBindingKind::Equality { term: From dd39d489930b3702ea4b454f489c77c68df4a330 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 8 Dec 2023 01:52:56 +0000 Subject: [PATCH 14/53] Don't pass lint back out of lint decorator --- clippy_utils/src/diagnostics.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/clippy_utils/src/diagnostics.rs b/clippy_utils/src/diagnostics.rs index 8b1773e48e43..77fa075b806e 100644 --- a/clippy_utils/src/diagnostics.rs +++ b/clippy_utils/src/diagnostics.rs @@ -49,7 +49,6 @@ pub fn span_lint(cx: &T, lint: &'static Lint, sp: impl Into( diag.help(help); } docs_link(diag, lint); - diag }); } @@ -134,7 +132,6 @@ pub fn span_lint_and_note( diag.note(note); } docs_link(diag, lint); - diag }); } @@ -152,7 +149,6 @@ where cx.struct_span_lint(lint, sp, msg.to_string(), |diag| { f(diag); docs_link(diag, lint); - diag }); } @@ -160,7 +156,6 @@ pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, s #[expect(clippy::disallowed_methods)] cx.tcx.struct_span_lint_hir(lint, hir_id, sp, msg.to_string(), |diag| { docs_link(diag, lint); - diag }); } @@ -176,7 +171,6 @@ pub fn span_lint_hir_and_then( cx.tcx.struct_span_lint_hir(lint, hir_id, sp, msg.to_string(), |diag| { f(diag); docs_link(diag, lint); - diag }); } From 57e692b415e1d2de98038c77b3a02eec9cba4f2a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 17 Dec 2023 21:48:57 +1100 Subject: [PATCH 15/53] Rename `Handler` as `DiagCtxt`. --- clippy_lints/src/doc/needless_doctest_main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/doc/needless_doctest_main.rs b/clippy_lints/src/doc/needless_doctest_main.rs index e019523e6098..ccd6f22146b9 100644 --- a/clippy_lints/src/doc/needless_doctest_main.rs +++ b/clippy_lints/src/doc/needless_doctest_main.rs @@ -6,7 +6,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::{CoroutineKind, Fn, FnRetTy, Item, ItemKind}; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::EmitterWriter; -use rustc_errors::Handler; +use rustc_errors::DiagCtxt; use rustc_lint::LateContext; use rustc_parse::maybe_new_parser_from_source_str; use rustc_parse::parser::ForceCollect; @@ -45,7 +45,7 @@ pub fn check( let fallback_bundle = rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false); let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle); - let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings(); + let handler = DiagCtxt::with_emitter(Box::new(emitter)).disable_warnings(); #[expect(clippy::arc_with_non_send_sync)] // `Lrc` is expected by with_span_handler let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sess = ParseSess::with_span_handler(handler, sm); From 9dee081b652f117aedfe1d125832b668502eaea0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 17 Dec 2023 22:01:06 +1100 Subject: [PATCH 16/53] Rename `EarlyErrorHandler` as `EarlyDiagCtxt`. --- src/driver.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/driver.rs b/src/driver.rs index 49f0cad08e01..af38dde254ed 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -18,7 +18,7 @@ extern crate rustc_span; use rustc_interface::interface; use rustc_session::config::ErrorOutputType; use rustc_session::parse::ParseSess; -use rustc_session::EarlyErrorHandler; +use rustc_session::EarlyDiagCtxt; use rustc_span::symbol::Symbol; use std::env; @@ -174,7 +174,7 @@ const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/ne #[allow(clippy::too_many_lines)] #[allow(clippy::ignored_unit_patterns)] pub fn main() { - let handler = EarlyErrorHandler::new(ErrorOutputType::default()); + let handler = EarlyDiagCtxt::new(ErrorOutputType::default()); rustc_driver::init_rustc_env_logger(&handler); From cc9195c6a32aea938b214ef9187ff42749a5f49a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 18 Dec 2023 07:52:43 +1100 Subject: [PATCH 17/53] Rename `ParseSess::with_span_handler` as `ParseSess::with_dcx`. --- clippy_lints/src/doc/needless_doctest_main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/doc/needless_doctest_main.rs b/clippy_lints/src/doc/needless_doctest_main.rs index ccd6f22146b9..b2ac39a8e9fa 100644 --- a/clippy_lints/src/doc/needless_doctest_main.rs +++ b/clippy_lints/src/doc/needless_doctest_main.rs @@ -46,9 +46,9 @@ pub fn check( rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false); let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle); let handler = DiagCtxt::with_emitter(Box::new(emitter)).disable_warnings(); - #[expect(clippy::arc_with_non_send_sync)] // `Lrc` is expected by with_span_handler + #[expect(clippy::arc_with_non_send_sync)] // `Lrc` is expected by with_dcx let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sess = ParseSess::with_span_handler(handler, sm); + let sess = ParseSess::with_dcx(handler, sm); let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) { Ok(p) => p, From 7a7b65483b5ba16e44a3ee7b49a76768ef25fea5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 18 Dec 2023 11:15:13 +1100 Subject: [PATCH 18/53] Rename many `DiagCtxt` and `EarlyDiagCtxt` locals. --- clippy_lints/src/doc/needless_doctest_main.rs | 4 ++-- src/driver.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/doc/needless_doctest_main.rs b/clippy_lints/src/doc/needless_doctest_main.rs index b2ac39a8e9fa..c639813a3f9a 100644 --- a/clippy_lints/src/doc/needless_doctest_main.rs +++ b/clippy_lints/src/doc/needless_doctest_main.rs @@ -45,10 +45,10 @@ pub fn check( let fallback_bundle = rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false); let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle); - let handler = DiagCtxt::with_emitter(Box::new(emitter)).disable_warnings(); + let dcx = DiagCtxt::with_emitter(Box::new(emitter)).disable_warnings(); #[expect(clippy::arc_with_non_send_sync)] // `Lrc` is expected by with_dcx let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sess = ParseSess::with_dcx(handler, sm); + let sess = ParseSess::with_dcx(dcx, sm); let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) { Ok(p) => p, diff --git a/src/driver.rs b/src/driver.rs index af38dde254ed..b944a299256c 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -174,9 +174,9 @@ const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/ne #[allow(clippy::too_many_lines)] #[allow(clippy::ignored_unit_patterns)] pub fn main() { - let handler = EarlyDiagCtxt::new(ErrorOutputType::default()); + let early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default()); - rustc_driver::init_rustc_env_logger(&handler); + rustc_driver::init_rustc_env_logger(&early_dcx); let using_internal_features = rustc_driver::install_ice_hook(BUG_REPORT_URL, |handler| { // FIXME: this macro calls unwrap internally but is called in a panicking context! It's not From 692636fabd46c155a39059299e09a452f1fda5ed Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Tue, 19 Dec 2023 22:47:30 +0000 Subject: [PATCH 19/53] Give `VariantData::Struct` named fields, to clairfy `recovered`. --- clippy_lints/src/item_name_repetitions.rs | 2 +- clippy_lints/src/manual_non_exhaustive.rs | 2 +- clippy_utils/src/ast_utils.rs | 4 +++- clippy_utils/src/check_proc_macro.rs | 4 ++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/item_name_repetitions.rs b/clippy_lints/src/item_name_repetitions.rs index b6aacba2517a..a9f1612ff05e 100644 --- a/clippy_lints/src/item_name_repetitions.rs +++ b/clippy_lints/src/item_name_repetitions.rs @@ -436,7 +436,7 @@ impl LateLintPass<'_> for ItemNameRepetitions { { match item.kind { ItemKind::Enum(def, _) => check_variant(cx, self.enum_threshold, &def, item_name, item.span), - ItemKind::Struct(VariantData::Struct(fields, _), _) => { + ItemKind::Struct(VariantData::Struct { fields, .. }, _) => { check_fields(cx, self.struct_threshold, item, fields); }, _ => (), diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 545b122930e5..d2ac0ad8363e 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -103,7 +103,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct { if let ast::ItemKind::Struct(variant_data, _) = &item.kind { let (fields, delimiter) = match variant_data { - ast::VariantData::Struct(fields, _) => (&**fields, '{'), + ast::VariantData::Struct { fields, .. } => (&**fields, '{'), ast::VariantData::Tuple(fields, _) => (&**fields, '('), ast::VariantData::Unit(_) => return, }; diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index e36f2fa87a72..c271e498665e 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -546,7 +546,9 @@ pub fn eq_variant_data(l: &VariantData, r: &VariantData) -> bool { use VariantData::*; match (l, r) { (Unit(_), Unit(_)) => true, - (Struct(l, _), Struct(r, _)) | (Tuple(l, _), Tuple(r, _)) => over(l, r, eq_struct_field), + (Struct { fields: l, .. }, Struct { fields: r, .. }) | (Tuple(l, _), Tuple(r, _)) => { + over(l, r, eq_struct_field) + }, _ => false, } } diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 470d31fa3e1a..d751aeaf9022 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -200,7 +200,7 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) { ItemKind::ForeignMod { .. } => (Pat::Str("extern"), Pat::Str("}")), ItemKind::TyAlias(..) | ItemKind::OpaqueTy(_) => (Pat::Str("type"), Pat::Str(";")), ItemKind::Enum(..) => (Pat::Str("enum"), Pat::Str("}")), - ItemKind::Struct(VariantData::Struct(..), _) => (Pat::Str("struct"), Pat::Str("}")), + ItemKind::Struct(VariantData::Struct { .. }, _) => (Pat::Str("struct"), Pat::Str("}")), ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")), ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")), ItemKind::Trait(_, Unsafety::Unsafe, ..) @@ -255,7 +255,7 @@ fn field_def_search_pat(def: &FieldDef<'_>) -> (Pat, Pat) { fn variant_search_pat(v: &Variant<'_>) -> (Pat, Pat) { match v.data { - VariantData::Struct(..) => (Pat::Sym(v.ident.name), Pat::Str("}")), + VariantData::Struct { .. } => (Pat::Sym(v.ident.name), Pat::Str("}")), VariantData::Tuple(..) => (Pat::Sym(v.ident.name), Pat::Str("")), VariantData::Unit(..) => (Pat::Sym(v.ident.name), Pat::Sym(v.ident.name)), } From 67d4b9855d3b471dde8e82535dbc5dc17445fcbd Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Fri, 8 Dec 2023 14:51:50 -0800 Subject: [PATCH 20/53] Plumb awaitness of for loops --- clippy_lints/src/needless_continue.rs | 6 +++++- clippy_lints/src/redundant_else.rs | 2 +- .../src/suspicious_operation_groupings.rs | 2 +- clippy_utils/src/ast_utils.rs | 19 ++++++++++++++++--- clippy_utils/src/sugg.rs | 2 +- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index 4b9ab50e4fd7..ff72b5e69ef1 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -220,7 +220,11 @@ where F: FnMut(&ast::Block, Option<&ast::Label>), { if let ast::ExprKind::While(_, loop_block, label) - | ast::ExprKind::ForLoop(_, _, loop_block, label) + | ast::ExprKind::ForLoop { + body: loop_block, + label, + .. + } | ast::ExprKind::Loop(loop_block, label, ..) = &expr.kind { func(loop_block, label.as_ref()); diff --git a/clippy_lints/src/redundant_else.rs b/clippy_lints/src/redundant_else.rs index 001686c84f81..fb434fb7450a 100644 --- a/clippy_lints/src/redundant_else.rs +++ b/clippy_lints/src/redundant_else.rs @@ -111,7 +111,7 @@ impl<'ast> Visitor<'ast> for BreakVisitor { ExprKind::If(_, ref then, Some(ref els)) => self.check_block(then) && self.check_expr(els), ExprKind::If(_, _, None) // ignore loops for simplicity - | ExprKind::While(..) | ExprKind::ForLoop(..) | ExprKind::Loop(..) => false, + | ExprKind::While(..) | ExprKind::ForLoop { .. } | ExprKind::Loop(..) => false, _ => { walk_expr(self, expr); return; diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index 8b9d9bade915..60e9d262e7e0 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -554,7 +554,7 @@ fn ident_difference_expr_with_base_location( | (Closure(_), Closure(_)) | (Match(_, _), Match(_, _)) | (Loop(_, _, _), Loop(_, _, _)) - | (ForLoop(_, _, _, _), ForLoop(_, _, _, _)) + | (ForLoop { .. }, ForLoop { .. }) | (While(_, _, _), While(_, _, _)) | (If(_, _, _), If(_, _, _)) | (Let(_, _, _, _), Let(_, _, _, _)) diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index c271e498665e..7fe76b946a4b 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -169,9 +169,22 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Let(lp, le, _, _), Let(rp, re, _, _)) => eq_pat(lp, rp) && eq_expr(le, re), (If(lc, lt, le), If(rc, rt, re)) => eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le, re), (While(lc, lt, ll), While(rc, rt, rl)) => eq_label(ll, rl) && eq_expr(lc, rc) && eq_block(lt, rt), - (ForLoop(lp, li, lt, ll), ForLoop(rp, ri, rt, rl)) => { - eq_label(ll, rl) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt) - }, + ( + ForLoop { + pat: lp, + iter: li, + body: lt, + label: ll, + kind: lk, + }, + ForLoop { + pat: rp, + iter: ri, + body: rt, + label: rl, + kind: rk, + }, + ) => eq_label(ll, rl) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt) && lk == rk, (Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll, rl) && eq_block(lt, rt), (Block(lb, ll), Block(rb, rl)) => eq_label(ll, rl) && eq_block(lb, rb), (TryBlock(l), TryBlock(r)) => eq_block(l, r), diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 9b2bc8df1f30..c86362c427ce 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -197,7 +197,7 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Continue(..) | ast::ExprKind::Yield(..) | ast::ExprKind::Field(..) - | ast::ExprKind::ForLoop(..) + | ast::ExprKind::ForLoop { .. } | ast::ExprKind::Index(..) | ast::ExprKind::InlineAsm(..) | ast::ExprKind::OffsetOf(..) From 42695d4bfc5484c6824f36093e9d273473d5bc32 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 21 Dec 2023 18:49:20 +0000 Subject: [PATCH 21/53] Split coroutine desugaring kind from source --- clippy_lints/src/async_yields_async.rs | 5 ++--- clippy_lints/src/await_holding_invalid.rs | 5 ++--- clippy_lints/src/manual_async_fn.rs | 4 ++-- clippy_lints/src/needless_question_mark.rs | 4 ++-- clippy_lints/src/redundant_async_block.rs | 4 ++-- clippy_lints/src/redundant_closure_call.rs | 4 ++-- clippy_lints/src/unused_async.rs | 8 +++++++- 7 files changed, 19 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs index 3e5a01c45df1..28e6614f03fb 100644 --- a/clippy_lints/src/async_yields_async.rs +++ b/clippy_lints/src/async_yields_async.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; -use rustc_hir::{Body, BodyId, CoroutineKind, CoroutineSource, ExprKind, QPath}; +use rustc_hir::{Body, BodyId, CoroutineKind, CoroutineSource, CoroutineDesugaring, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -45,10 +45,9 @@ declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]); impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { - use CoroutineSource::{Block, Closure}; // For functions, with explicitly defined types, don't warn. // XXXkhuey maybe we should? - if let Some(CoroutineKind::Async(Block | Closure)) = body.coroutine_kind { + if let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block | CoroutineSource::Closure)) = body.coroutine_kind { if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() { let body_id = BodyId { hir_id: body.value.hir_id, diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index 9894a1639618..dff6e884fa11 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{match_def_path, paths}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; -use rustc_hir::{Body, CoroutineKind, CoroutineSource}; +use rustc_hir::{Body, CoroutineKind, CoroutineDesugaring}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::CoroutineLayout; use rustc_session::impl_lint_pass; @@ -194,8 +194,7 @@ impl LateLintPass<'_> for AwaitHolding { } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - use CoroutineSource::{Block, Closure, Fn}; - if let Some(CoroutineKind::Async(Block | Closure | Fn)) = body.coroutine_kind { + if let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) = body.coroutine_kind { let def_id = cx.tcx.hir().body_owner_def_id(body.id()); if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(def_id) { self.check_interior_types(cx, coroutine_layout); diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index eaaaea0be9f8..8982ce5e196e 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -3,7 +3,7 @@ use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt}; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - Block, Body, Closure, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound, + Block, Body, Closure, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind, }; use rustc_lint::{LateContext, LateLintPass}; @@ -178,7 +178,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) .. } = block_expr && let closure_body = cx.tcx.hir().body(body) - && closure_body.coroutine_kind == Some(CoroutineKind::Async(CoroutineSource::Block)) + && closure_body.coroutine_kind == Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block)) { return Some(closure_body); } diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index a4d3aaf0de98..350707d3a136 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -3,7 +3,7 @@ use clippy_utils::path_res; use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Block, Body, CoroutineKind, CoroutineSource, Expr, ExprKind, LangItem, MatchSource, QPath}; +use rustc_hir::{Block, Body, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -86,7 +86,7 @@ impl LateLintPass<'_> for NeedlessQuestionMark { } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - if let Some(CoroutineKind::Async(CoroutineSource::Fn)) = body.coroutine_kind { + if let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Fn)) = body.coroutine_kind { if let ExprKind::Block( Block { expr: diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 19d9d64b31e3..4b3fe9c0bb55 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -5,7 +5,7 @@ use clippy_utils::peel_blocks; use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::visitors::for_each_expr; use rustc_errors::Applicability; -use rustc_hir::{Closure, CoroutineKind, CoroutineSource, Expr, ExprKind, MatchSource}; +use rustc_hir::{Closure, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::UpvarCapture; @@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind && let body = cx.tcx.hir().body(*body) - && matches!(body.coroutine_kind, Some(CoroutineKind::Async(CoroutineSource::Block))) + && matches!(body.coroutine_kind, Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block))) { cx.typeck_results() .closure_min_captures diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index 8bac2e40e012..9312a9c89b78 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -5,7 +5,7 @@ use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor}; -use rustc_hir::{intravisit as hir_visit, CoroutineKind, CoroutineSource, Node}; +use rustc_hir::{intravisit as hir_visit, CoroutineKind, CoroutineSource, CoroutineDesugaring, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; @@ -67,7 +67,7 @@ fn is_async_closure(cx: &LateContext<'_>, body: &hir::Body<'_>) -> bool { if let hir::ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind && let desugared_inner_closure_body = cx.tcx.hir().body(innermost_closure_generated_by_desugar.body) // checks whether it is `async || whatever_expression` - && let Some(CoroutineKind::Async(CoroutineSource::Closure)) = desugared_inner_closure_body.coroutine_kind + && let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)) = desugared_inner_closure_body.coroutine_kind { true } else { diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index 9c8c44c0a16d..f71fe4e1e92e 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -86,7 +86,13 @@ impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> { } fn visit_body(&mut self, b: &'tcx Body<'tcx>) { - let is_async_block = matches!(b.coroutine_kind, Some(rustc_hir::CoroutineKind::Async(_))); + let is_async_block = matches!( + b.coroutine_kind, + Some(rustc_hir::CoroutineKind::Desugared( + rustc_hir::CoroutineDesugaring::Async, + _ + )) + ); if is_async_block { self.async_depth += 1; From cce967e92d0ad122fa256a2b2879c8db387f9108 Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Fri, 22 Dec 2023 23:29:20 +0000 Subject: [PATCH 22/53] bool->enum for ast::PatKind::Struct presence of `..` See https://github.com/rust-lang/rust/blob/cee794ee98d49b45a55ba225680d98e0c4672736/compiler/rustc_parse/src/parser/pat.rs#L890-L897 for the only place this is constructed. --- clippy_lints/src/unnested_or_patterns.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 65600009c1d7..77adcdd0e6bf 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -293,7 +293,7 @@ fn extend_with_struct_pat( qself1: &Option>, path1: &ast::Path, fps1: &mut [ast::PatField], - rest1: bool, + rest1: ast::PatFieldsRest, start: usize, alternatives: &mut ThinVec>, ) -> bool { From e4a9ba88e92eafcf2a76536da9c140d9af8978fc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 18 Dec 2023 22:21:37 +1100 Subject: [PATCH 23/53] Remove `Session` methods that duplicate `DiagCtxt` methods. Also add some `dcx` methods to types that wrap `TyCtxt`, for easier access. --- clippy_config/src/conf.rs | 10 +++++----- clippy_config/src/msrvs.rs | 8 ++++---- clippy_lints/src/missing_const_for_fn.rs | 2 +- clippy_utils/src/attrs.rs | 10 +++++----- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 88611eb70878..3cf4377002a8 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -636,11 +636,11 @@ impl Conf { match path { Ok((_, warnings)) => { for warning in warnings { - sess.warn(warning.clone()); + sess.dcx().warn(warning.clone()); } }, Err(error) => { - sess.err(format!("error finding Clippy's configuration file: {error}")); + sess.dcx().err(format!("error finding Clippy's configuration file: {error}")); }, } @@ -652,7 +652,7 @@ impl Conf { Ok((Some(path), _)) => match sess.source_map().load_file(path) { Ok(file) => deserialize(&file), Err(error) => { - sess.err(format!("failed to read `{}`: {error}", path.display())); + sess.dcx().err(format!("failed to read `{}`: {error}", path.display())); TryConf::default() }, }, @@ -663,14 +663,14 @@ impl Conf { // all conf errors are non-fatal, we just use the default conf in case of error for error in errors { - sess.span_err( + sess.dcx().span_err( error.span, format!("error reading Clippy's configuration file: {}", error.message), ); } for warning in warnings { - sess.span_warn( + sess.dcx().span_warn( warning.span, format!("error reading Clippy's configuration file: {}", warning.message), ); diff --git a/clippy_config/src/msrvs.rs b/clippy_config/src/msrvs.rs index b3ef666e3063..13e61e5a0326 100644 --- a/clippy_config/src/msrvs.rs +++ b/clippy_config/src/msrvs.rs @@ -83,7 +83,7 @@ impl Msrv { (None, Some(cargo_msrv)) => self.stack = vec![cargo_msrv], (Some(clippy_msrv), Some(cargo_msrv)) => { if clippy_msrv != cargo_msrv { - sess.warn(format!( + sess.dcx().warn(format!( "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`" )); } @@ -106,7 +106,7 @@ impl Msrv { if let Some(msrv_attr) = msrv_attrs.next() { if let Some(duplicate) = msrv_attrs.last() { - sess.struct_span_err(duplicate.span, "`clippy::msrv` is defined multiple times") + sess.dcx().struct_span_err(duplicate.span, "`clippy::msrv` is defined multiple times") .span_note(msrv_attr.span, "first definition found here") .emit(); } @@ -116,9 +116,9 @@ impl Msrv { return Some(version); } - sess.span_err(msrv_attr.span, format!("`{msrv}` is not a valid Rust version")); + sess.dcx().span_err(msrv_attr.span, format!("`{msrv}` is not a valid Rust version")); } else { - sess.span_err(msrv_attr.span, "bad clippy attribute"); + sess.dcx().span_err(msrv_attr.span, "bad clippy attribute"); } } diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index acaa6be30092..9ba19e0a8658 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -153,7 +153,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, &self.msrv) { if cx.tcx.is_const_fn_raw(def_id.to_def_id()) { - cx.tcx.sess.span_err(span, err); + cx.tcx.dcx().span_err(span, err); } } else { span_lint(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`"); diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 51771f78d4ff..46c96fad884f 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -76,12 +76,12 @@ pub fn get_attr<'a>( }) .map_or_else( || { - sess.span_err(attr_segments[1].ident.span, "usage of unknown attribute"); + sess.dcx().span_err(attr_segments[1].ident.span, "usage of unknown attribute"); false }, |deprecation_status| { let mut diag = - sess.struct_span_err(attr_segments[1].ident.span, "usage of deprecated attribute"); + sess.dcx().struct_span_err(attr_segments[1].ident.span, "usage of deprecated attribute"); match *deprecation_status { DeprecationStatus::Deprecated => { diag.emit(); @@ -116,10 +116,10 @@ fn parse_attrs(sess: &Session, attrs: &[ast::Attribute], name: &' if let Ok(value) = FromStr::from_str(value.as_str()) { f(value); } else { - sess.span_err(attr.span, "not a number"); + sess.dcx().span_err(attr.span, "not a number"); } } else { - sess.span_err(attr.span, "bad clippy attribute"); + sess.dcx().span_err(attr.span, "bad clippy attribute"); } } } @@ -132,7 +132,7 @@ pub fn get_unique_attr<'a>( let mut unique_attr: Option<&ast::Attribute> = None; for attr in get_attr(sess, attrs, name) { if let Some(duplicate) = unique_attr { - sess.struct_span_err(attr.span, format!("`{name}` is defined multiple times")) + sess.dcx().struct_span_err(attr.span, format!("`{name}` is defined multiple times")) .span_note(duplicate.span, "first definition found here") .emit(); } else { From 9d0924f0e37e0e91db0a17863e34a836f3503765 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 25 Dec 2023 18:01:56 +0000 Subject: [PATCH 24/53] Fix clippy's usage of Body's coroutine_kind Also fixes a bug where we weren't peeling blocks from async bodies --- clippy_lints/src/async_yields_async.rs | 23 +++++++++++----- clippy_lints/src/await_holding_invalid.rs | 18 +++++++----- clippy_lints/src/manual_async_fn.rs | 32 ++++++++++++++-------- clippy_lints/src/methods/iter_kv_map.rs | 1 - clippy_lints/src/needless_question_mark.rs | 32 ++++++++++------------ clippy_lints/src/redundant_async_block.rs | 6 ++-- clippy_lints/src/redundant_closure_call.rs | 9 +++--- clippy_lints/src/unused_async.rs | 28 +++++++++---------- clippy_lints/src/utils/author.rs | 21 +++++++++++--- tests/ui/author/blocks.stdout | 4 +-- tests/ui/author/macro_in_closure.stdout | 2 +- tests/ui/needless_question_mark.fixed | 4 +++ tests/ui/needless_question_mark.rs | 4 +++ tests/ui/needless_question_mark.stderr | 8 +++++- 14 files changed, 119 insertions(+), 73 deletions(-) diff --git a/clippy_lints/src/async_yields_async.rs b/clippy_lints/src/async_yields_async.rs index 28e6614f03fb..c965341d3fdf 100644 --- a/clippy_lints/src/async_yields_async.rs +++ b/clippy_lints/src/async_yields_async.rs @@ -2,7 +2,9 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; -use rustc_hir::{Body, BodyId, CoroutineKind, CoroutineSource, CoroutineDesugaring, ExprKind, QPath}; +use rustc_hir::{ + Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, QPath, +}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -44,15 +46,22 @@ declare_clippy_lint! { declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]); impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { - fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { // For functions, with explicitly defined types, don't warn. // XXXkhuey maybe we should? - if let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block | CoroutineSource::Closure)) = body.coroutine_kind { + if let ExprKind::Closure(Closure { + kind: + ClosureKind::Coroutine(CoroutineKind::Desugared( + CoroutineDesugaring::Async, + CoroutineSource::Block | CoroutineSource::Closure, + )), + body: body_id, + .. + }) = expr.kind + { if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() { - let body_id = BodyId { - hir_id: body.value.hir_id, - }; - let typeck_results = cx.tcx.typeck_body(body_id); + let typeck_results = cx.tcx.typeck_body(*body_id); + let body = cx.tcx.hir().body(*body_id); let expr_ty = typeck_results.expr_ty(body.value); if implements_trait(cx, expr_ty, future_trait_def_id, &[]) { diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index dff6e884fa11..765cc7c0a54f 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -2,8 +2,8 @@ use clippy_config::types::DisallowedPath; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{match_def_path, paths}; use rustc_data_structures::fx::FxHashMap; +use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_hir::{Body, CoroutineKind, CoroutineDesugaring}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::CoroutineLayout; use rustc_session::impl_lint_pass; @@ -183,8 +183,8 @@ impl AwaitHolding { } } -impl LateLintPass<'_> for AwaitHolding { - fn check_crate(&mut self, cx: &LateContext<'_>) { +impl<'tcx> LateLintPass<'tcx> for AwaitHolding { + fn check_crate(&mut self, cx: &LateContext<'tcx>) { for conf in &self.conf_invalid_types { let segs: Vec<_> = conf.path().split("::").collect(); for id in clippy_utils::def_path_def_ids(cx, &segs) { @@ -193,10 +193,14 @@ impl LateLintPass<'_> for AwaitHolding { } } - fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - if let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) = body.coroutine_kind { - let def_id = cx.tcx.hir().body_owner_def_id(body.id()); - if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(def_id) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { + if let hir::ExprKind::Closure(hir::Closure { + kind: hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)), + def_id, + .. + }) = expr.kind + { + if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(*def_id) { self.check_interior_types(cx, coroutine_layout); } } diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 8982ce5e196e..9ba1d3afcbe9 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -3,8 +3,9 @@ use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt}; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - Block, Body, Closure, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound, - ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind, + Block, Body, Closure, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl, FnRetTy, + GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, + TypeBindingKind, ClosureKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -171,16 +172,25 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName]) .all(|in_lt| output_lifetimes.iter().any(|out_lt| in_lt == out_lt)) } -fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> { - if let Some(block_expr) = block.expr - && let Expr { - kind: ExprKind::Closure(&Closure { body, .. }), - .. - } = block_expr - && let closure_body = cx.tcx.hir().body(body) - && closure_body.coroutine_kind == Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block)) +fn desugared_async_block<'tcx>( + cx: &LateContext<'tcx>, + block: &'tcx Block<'tcx>, +) -> Option<&'tcx Body<'tcx>> { + if let Some(Expr { + kind: + ExprKind::Closure(&Closure { + kind: + ClosureKind::Coroutine(CoroutineKind::Desugared( + CoroutineDesugaring::Async, + CoroutineSource::Block, + )), + body, + .. + }), + .. + }) = block.expr { - return Some(closure_body); + return Some(cx.tcx.hir().body(body)); } None diff --git a/clippy_lints/src/methods/iter_kv_map.rs b/clippy_lints/src/methods/iter_kv_map.rs index e1b934d36ea8..6394f35f8604 100644 --- a/clippy_lints/src/methods/iter_kv_map.rs +++ b/clippy_lints/src/methods/iter_kv_map.rs @@ -32,7 +32,6 @@ pub(super) fn check<'tcx>( && let Body { params: [p], value: body_expr, - coroutine_kind: _, } = cx.tcx.hir().body(c.body) && let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind && let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) { diff --git a/clippy_lints/src/needless_question_mark.rs b/clippy_lints/src/needless_question_mark.rs index 350707d3a136..d7adf22ff32a 100644 --- a/clippy_lints/src/needless_question_mark.rs +++ b/clippy_lints/src/needless_question_mark.rs @@ -3,7 +3,7 @@ use clippy_utils::path_res; use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Block, Body, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, LangItem, MatchSource, QPath}; +use rustc_hir::{Block, Body, Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -86,22 +86,20 @@ impl LateLintPass<'_> for NeedlessQuestionMark { } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - if let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Fn)) = body.coroutine_kind { - if let ExprKind::Block( - Block { - expr: - Some(Expr { - kind: ExprKind::DropTemps(async_body), - .. - }), - .. - }, - _, - ) = body.value.kind - { - if let ExprKind::Block(Block { expr: Some(expr), .. }, ..) = async_body.kind { - check(cx, expr); - } + if let ExprKind::Block( + Block { + expr: + Some(Expr { + kind: ExprKind::DropTemps(async_body), + .. + }), + .. + }, + _, + ) = body.value.kind + { + if let ExprKind::Block(Block { expr: Some(expr), .. }, ..) = async_body.kind { + check(cx, expr.peel_blocks()); } } else { check(cx, body.value.peel_blocks()); diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs index 4b3fe9c0bb55..b50141f048c5 100644 --- a/clippy_lints/src/redundant_async_block.rs +++ b/clippy_lints/src/redundant_async_block.rs @@ -5,7 +5,7 @@ use clippy_utils::peel_blocks; use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::visitors::for_each_expr; use rustc_errors::Applicability; -use rustc_hir::{Closure, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, MatchSource}; +use rustc_hir::{Closure, ClosureKind, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::UpvarCapture; @@ -69,9 +69,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { /// If `expr` is a desugared `async` block, return the original expression if it does not capture /// any variable by ref. fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { - if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind + if let ExprKind::Closure(Closure { body, def_id, kind, .. }) = expr.kind && let body = cx.tcx.hir().body(*body) - && matches!(body.coroutine_kind, Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block))) + && matches!(kind, ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block))) { cx.typeck_results() .closure_min_captures diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index 9312a9c89b78..16c929edb928 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -5,7 +5,7 @@ use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor}; -use rustc_hir::{intravisit as hir_visit, CoroutineKind, CoroutineSource, CoroutineDesugaring, Node}; +use rustc_hir::{intravisit as hir_visit, CoroutineKind, CoroutineSource, CoroutineDesugaring, Node, ClosureKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; @@ -63,11 +63,10 @@ impl<'tcx> Visitor<'tcx> for ReturnVisitor { /// Checks if the body is owned by an async closure. /// Returns true for `async || whatever_expression`, but false for `|| async { whatever_expression /// }`. -fn is_async_closure(cx: &LateContext<'_>, body: &hir::Body<'_>) -> bool { +fn is_async_closure(body: &hir::Body<'_>) -> bool { if let hir::ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind - && let desugared_inner_closure_body = cx.tcx.hir().body(innermost_closure_generated_by_desugar.body) // checks whether it is `async || whatever_expression` - && let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)) = desugared_inner_closure_body.coroutine_kind + && let ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)) = innermost_closure_generated_by_desugar.kind { true } else { @@ -103,7 +102,7 @@ fn find_innermost_closure<'tcx>( data = Some(( body.value, closure.fn_decl, - if is_async_closure(cx, body) { + if is_async_closure(body) { ty::Asyncness::Yes } else { ty::Asyncness::No diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index f71fe4e1e92e..1d42375ba8e5 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::is_def_id_trait_method; use rustc_hir::def::DefKind; -use rustc_hir::intravisit::{walk_body, walk_expr, walk_fn, FnKind, Visitor}; +use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor}; use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; @@ -78,32 +78,32 @@ impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> { self.await_in_async_block = Some(ex.span); } } - walk_expr(self, ex); - } - - fn nested_visit_map(&mut self) -> Self::Map { - self.cx.tcx.hir() - } - fn visit_body(&mut self, b: &'tcx Body<'tcx>) { let is_async_block = matches!( - b.coroutine_kind, - Some(rustc_hir::CoroutineKind::Desugared( - rustc_hir::CoroutineDesugaring::Async, - _ - )) + ex.kind, + ExprKind::Closure(rustc_hir::Closure { + kind: rustc_hir::ClosureKind::Coroutine(rustc_hir::CoroutineKind::Desugared( + rustc_hir::CoroutineDesugaring::Async, + _ + )), + .. + }) ); if is_async_block { self.async_depth += 1; } - walk_body(self, b); + walk_expr(self, ex); if is_async_block { self.async_depth -= 1; } } + + fn nested_visit_map(&mut self) -> Self::Map { + self.cx.tcx.hir() + } } impl<'tcx> LateLintPass<'tcx> for UnusedAsync { diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index a8bf142f5d53..8817e46b3c8c 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -7,7 +7,8 @@ use rustc_ast::LitIntType; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::{ - ArrayLen, BindingAnnotation, CaptureBy, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind, + ArrayLen, BindingAnnotation, CaptureBy, Closure, ClosureKind, CoroutineKind, ExprKind, FnRetTy, HirId, Lit, + PatKind, QPath, StmtKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; @@ -477,7 +478,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { capture_clause, fn_decl, body: body_id, - movability, + kind, .. }) => { let capture_clause = match capture_clause { @@ -485,7 +486,17 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { CaptureBy::Ref => "Ref", }; - let movability = OptionPat::new(movability.map(|m| format!("Movability::{m:?}"))); + let closure_kind = match kind { + ClosureKind::Closure => "ClosureKind::Closure".to_string(), + ClosureKind::Coroutine(coroutine_kind) => match coroutine_kind { + CoroutineKind::Desugared(desugaring, source) => format!( + "ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::{desugaring:?}, CoroutineSource::{source:?}))" + ), + CoroutineKind::Coroutine(movability) => { + format!("ClosureKind::Coroutine(CoroutineKind::Coroutine(Movability::{movability:?})") + }, + }, + }; let ret_ty = match fn_decl.output { FnRetTy::DefaultReturn(_) => "FnRetTy::DefaultReturn(_)", @@ -493,7 +504,9 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { }; bind!(self, fn_decl, body_id); - kind!("Closure(CaptureBy::{capture_clause}, {fn_decl}, {body_id}, _, {movability})"); + kind!( + "Closure {{ capture_clause: CaptureBy::{capture_clause}, fn_decl: {fn_decl}, body: {body_id}, closure_kind: {closure_kind}, .. }}" + ); chain!(self, "let {ret_ty} = {fn_decl}.output"); self.body(body_id); }, diff --git a/tests/ui/author/blocks.stdout b/tests/ui/author/blocks.stdout index 140300a16730..62de661f8ff8 100644 --- a/tests/ui/author/blocks.stdout +++ b/tests/ui/author/blocks.stdout @@ -40,10 +40,10 @@ if let ExprKind::Block(block, None) = expr.kind { // report your lint here } -if let ExprKind::Closure(CaptureBy::Value { .. }, fn_decl, body_id, _, None) = expr.kind +if let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_decl, body: body_id, closure_kind: ClosureKind::Closure, .. } = expr.kind && let FnRetTy::DefaultReturn(_) = fn_decl.output && expr1 = &cx.tcx.hir().body(body_id).value - && let ExprKind::Closure(CaptureBy::Value { .. }, fn_decl1, body_id1, _, Some(Movability::Static)) = expr1.kind + && let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_decl1, body: body_id1, closure_kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)), .. } = expr1.kind && let FnRetTy::DefaultReturn(_) = fn_decl1.output && expr2 = &cx.tcx.hir().body(body_id1).value && let ExprKind::Block(block, None) = expr2.kind diff --git a/tests/ui/author/macro_in_closure.stdout b/tests/ui/author/macro_in_closure.stdout index 9ab71986f40f..06386d1d7ec4 100644 --- a/tests/ui/author/macro_in_closure.stdout +++ b/tests/ui/author/macro_in_closure.stdout @@ -1,6 +1,6 @@ if let StmtKind::Local(local) = stmt.kind && let Some(init) = local.init - && let ExprKind::Closure(CaptureBy::Ref, fn_decl, body_id, _, None) = init.kind + && let ExprKind::Closure { capture_clause: CaptureBy::Ref, fn_decl: fn_decl, body: body_id, closure_kind: ClosureKind::Closure, .. } = init.kind && let FnRetTy::DefaultReturn(_) = fn_decl.output && expr = &cx.tcx.hir().body(body_id).value && let ExprKind::Block(block, None) = expr.kind diff --git a/tests/ui/needless_question_mark.fixed b/tests/ui/needless_question_mark.fixed index 07bd6b6f3c1e..92f01c217c1c 100644 --- a/tests/ui/needless_question_mark.fixed +++ b/tests/ui/needless_question_mark.fixed @@ -135,3 +135,7 @@ async fn async_deref_ref(s: Option<&String>) -> Option<&str> { async fn async_result_bad(s: TR) -> Result { s.magic } + +async fn async_wrapped(a: Option) -> Option { + { a } +} diff --git a/tests/ui/needless_question_mark.rs b/tests/ui/needless_question_mark.rs index fbf8a12fd504..21c858c291ff 100644 --- a/tests/ui/needless_question_mark.rs +++ b/tests/ui/needless_question_mark.rs @@ -135,3 +135,7 @@ async fn async_deref_ref(s: Option<&String>) -> Option<&str> { async fn async_result_bad(s: TR) -> Result { Ok(s.magic?) } + +async fn async_wrapped(a: Option) -> Option { + { Some(a?) } +} diff --git a/tests/ui/needless_question_mark.stderr b/tests/ui/needless_question_mark.stderr index cd961a49f421..bf090302ef7e 100644 --- a/tests/ui/needless_question_mark.stderr +++ b/tests/ui/needless_question_mark.stderr @@ -90,5 +90,11 @@ error: question mark operator is useless here LL | Ok(s.magic?) | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `s.magic` -error: aborting due to 14 previous errors +error: question mark operator is useless here + --> $DIR/needless_question_mark.rs:140:7 + | +LL | { Some(a?) } + | ^^^^^^^^ help: try removing question mark and `Some()`: `a` + +error: aborting due to 15 previous errors From 86f3749ea95b506d76336ff1dba5216531f3dedb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 23 Dec 2023 04:02:17 +0000 Subject: [PATCH 25/53] Make some non-diagnostic-affecting QPath::LangItem into regular qpaths --- tests/ui/author/macro_in_closure.stdout | 2 ++ tests/ui/author/macro_in_loop.stdout | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/ui/author/macro_in_closure.stdout b/tests/ui/author/macro_in_closure.stdout index 06386d1d7ec4..f2e54c2c1c86 100644 --- a/tests/ui/author/macro_in_closure.stdout +++ b/tests/ui/author/macro_in_closure.stdout @@ -12,6 +12,7 @@ if let StmtKind::Local(local) = stmt.kind && args.len() == 1 && let ExprKind::Call(func1, args1) = args[0].kind && let ExprKind::Path(ref qpath1) = func1.kind + && match_qpath(qpath1, &["format_arguments", "new_v1"]) && args1.len() == 2 && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind && let ExprKind::Array(elements) = inner.kind @@ -27,6 +28,7 @@ if let StmtKind::Local(local) = stmt.kind && elements1.len() == 1 && let ExprKind::Call(func2, args2) = elements1[0].kind && let ExprKind::Path(ref qpath2) = func2.kind + && match_qpath(qpath2, &["format_argument", "new_display"]) && args2.len() == 1 && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind && let ExprKind::Path(ref qpath3) = inner2.kind diff --git a/tests/ui/author/macro_in_loop.stdout b/tests/ui/author/macro_in_loop.stdout index bd054b6abc43..a719e3af7e76 100644 --- a/tests/ui/author/macro_in_loop.stdout +++ b/tests/ui/author/macro_in_loop.stdout @@ -22,6 +22,7 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo && args.len() == 1 && let ExprKind::Call(func1, args1) = args[0].kind && let ExprKind::Path(ref qpath2) = func1.kind + && match_qpath(qpath2, &["format_arguments", "new_v1"]) && args1.len() == 2 && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind && let ExprKind::Array(elements) = inner.kind @@ -37,6 +38,7 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo && elements1.len() == 1 && let ExprKind::Call(func2, args2) = elements1[0].kind && let ExprKind::Path(ref qpath3) = func2.kind + && match_qpath(qpath3, &["format_argument", "new_display"]) && args2.len() == 1 && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind && let ExprKind::Path(ref qpath4) = inner2.kind From 03be3e742f0559c5549ee86587ae4715508b5a96 Mon Sep 17 00:00:00 2001 From: Hamir Mahal Date: Sun, 10 Dec 2023 15:44:34 -0800 Subject: [PATCH 26/53] fix: broken GitHub corner, with working dark/light --- util/gh-pages/index.html | 80 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/util/gh-pages/index.html b/util/gh-pages/index.html index 99e211654d19..a54b9a6409ec 100644 --- a/util/gh-pages/index.html +++ b/util/gh-pages/index.html @@ -566,8 +566,84 @@

- - Fork me on GitHub + + + From 6627705ecd7d9c8c9f6a5b062fc58c88fcc2caa1 Mon Sep 17 00:00:00 2001 From: Hamir Mahal Date: Sun, 10 Dec 2023 17:28:26 -0800 Subject: [PATCH 27/53] refactor: use CSS vars for GitHub Corner colors --- util/gh-pages/index.html | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/util/gh-pages/index.html b/util/gh-pages/index.html index a54b9a6409ec..a5274eeb349d 100644 --- a/util/gh-pages/index.html +++ b/util/gh-pages/index.html @@ -594,29 +594,19 @@

>