From e51e9308d58be45bffaf05c66af71681aaafd431 Mon Sep 17 00:00:00 2001 From: kraktus Date: Wed, 12 Oct 2022 12:04:41 +0200 Subject: [PATCH 1/3] `default_numeric_fallback` do not lint on constants --- clippy_lints/src/default_numeric_fallback.rs | 27 +++++++++------- tests/ui/default_numeric_fallback_f64.fixed | 9 ++++++ tests/ui/default_numeric_fallback_f64.rs | 9 ++++++ tests/ui/default_numeric_fallback_f64.stderr | 34 ++++++++++++-------- tests/ui/default_numeric_fallback_i32.fixed | 10 ++++++ tests/ui/default_numeric_fallback_i32.rs | 10 ++++++ tests/ui/default_numeric_fallback_i32.stderr | 34 ++++++++++++-------- 7 files changed, 93 insertions(+), 40 deletions(-) diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 3ed9cd36a229..8b5c9d25dc85 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::numeric_literal; use clippy_utils::source::snippet_opt; +use clippy_utils::{get_parent_node, numeric_literal}; use if_chain::if_chain; use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::{ intravisit::{walk_expr, walk_stmt, Visitor}, - Body, Expr, ExprKind, HirId, Lit, Stmt, StmtKind, + Body, Expr, ExprKind, HirId, ItemKind, Lit, Node, Stmt, StmtKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::{ @@ -55,7 +55,12 @@ declare_lint_pass!(DefaultNumericFallback => [DEFAULT_NUMERIC_FALLBACK]); impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback { fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { - let mut visitor = NumericFallbackVisitor::new(cx); + let is_parent_const = if let Some(Node::Item(item)) = get_parent_node(cx.tcx, body.id().hir_id) { + matches!(item.kind, ItemKind::Const(..)) + } else { + false + }; + let mut visitor = NumericFallbackVisitor::new(cx, is_parent_const); visitor.visit_body(body); } } @@ -68,9 +73,13 @@ struct NumericFallbackVisitor<'a, 'tcx> { } impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> { - fn new(cx: &'a LateContext<'tcx>) -> Self { + fn new(cx: &'a LateContext<'tcx>, is_parent_const: bool) -> Self { Self { - ty_bounds: vec![TyBound::Nothing], + ty_bounds: vec![if is_parent_const { + TyBound::Any + } else { + TyBound::Nothing + }], cx, } } @@ -192,13 +201,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) { match stmt.kind { - StmtKind::Local(local) => { - if local.ty.is_some() { - self.ty_bounds.push(TyBound::Any); - } else { - self.ty_bounds.push(TyBound::Nothing); - } - }, + StmtKind::Local(local) if local.ty.is_some() => self.ty_bounds.push(TyBound::Any), _ => self.ty_bounds.push(TyBound::Nothing), } diff --git a/tests/ui/default_numeric_fallback_f64.fixed b/tests/ui/default_numeric_fallback_f64.fixed index a28bff76755b..a370ccc76962 100644 --- a/tests/ui/default_numeric_fallback_f64.fixed +++ b/tests/ui/default_numeric_fallback_f64.fixed @@ -33,6 +33,7 @@ mod basic_expr { let x: [f64; 3] = [1., 2., 3.]; let x: (f64, f64) = if true { (1., 2.) } else { (3., 4.) }; let x: _ = 1.; + const X: f32 = 1.; } } @@ -59,6 +60,14 @@ mod nested_local { // Should NOT lint this because this literal is bound to `_` of outer `Local`. 2. }; + + const X: f32 = { + // Should lint this because this literal is not bound to any types. + let y = 1.0_f64; + + // Should NOT lint this because this literal is bound to `_` of outer `Local`. + 1. + }; } } diff --git a/tests/ui/default_numeric_fallback_f64.rs b/tests/ui/default_numeric_fallback_f64.rs index b48435cc7b28..2476fe95141d 100644 --- a/tests/ui/default_numeric_fallback_f64.rs +++ b/tests/ui/default_numeric_fallback_f64.rs @@ -33,6 +33,7 @@ mod basic_expr { let x: [f64; 3] = [1., 2., 3.]; let x: (f64, f64) = if true { (1., 2.) } else { (3., 4.) }; let x: _ = 1.; + const X: f32 = 1.; } } @@ -59,6 +60,14 @@ mod nested_local { // Should NOT lint this because this literal is bound to `_` of outer `Local`. 2. }; + + const X: f32 = { + // Should lint this because this literal is not bound to any types. + let y = 1.; + + // Should NOT lint this because this literal is bound to `_` of outer `Local`. + 1. + }; } } diff --git a/tests/ui/default_numeric_fallback_f64.stderr b/tests/ui/default_numeric_fallback_f64.stderr index f8b6c7746edb..5df2f642388d 100644 --- a/tests/ui/default_numeric_fallback_f64.stderr +++ b/tests/ui/default_numeric_fallback_f64.stderr @@ -61,79 +61,85 @@ LL | _ => 1., | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_f64.rs:43:21 + --> $DIR/default_numeric_fallback_f64.rs:44:21 | LL | let y = 1.; | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_f64.rs:51:21 + --> $DIR/default_numeric_fallback_f64.rs:52:21 | LL | let y = 1.; | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_f64.rs:57:21 + --> $DIR/default_numeric_fallback_f64.rs:58:21 | LL | let y = 1.; | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_f64.rs:69:9 + --> $DIR/default_numeric_fallback_f64.rs:66:21 + | +LL | let y = 1.; + | ^^ help: consider adding suffix: `1.0_f64` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback_f64.rs:78:9 | LL | 1. | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_f64.rs:75:27 + --> $DIR/default_numeric_fallback_f64.rs:84:27 | LL | let f = || -> _ { 1. }; | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_f64.rs:79:29 + --> $DIR/default_numeric_fallback_f64.rs:88:29 | LL | let f = || -> f64 { 1. }; | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_f64.rs:93:21 + --> $DIR/default_numeric_fallback_f64.rs:102:21 | LL | generic_arg(1.); | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_f64.rs:96:32 + --> $DIR/default_numeric_fallback_f64.rs:105:32 | LL | let x: _ = generic_arg(1.); | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_f64.rs:114:28 + --> $DIR/default_numeric_fallback_f64.rs:123:28 | LL | GenericStruct { x: 1. }; | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_f64.rs:117:36 + --> $DIR/default_numeric_fallback_f64.rs:126:36 | LL | let _ = GenericStruct { x: 1. }; | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_f64.rs:135:24 + --> $DIR/default_numeric_fallback_f64.rs:144:24 | LL | GenericEnum::X(1.); | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_f64.rs:155:23 + --> $DIR/default_numeric_fallback_f64.rs:164:23 | LL | s.generic_arg(1.); | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_f64.rs:162:21 + --> $DIR/default_numeric_fallback_f64.rs:171:21 | LL | let x = 22.; | ^^^ help: consider adding suffix: `22.0_f64` @@ -143,5 +149,5 @@ LL | internal_macro!(); | = note: this error originates in the macro `internal_macro` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 23 previous errors +error: aborting due to 24 previous errors diff --git a/tests/ui/default_numeric_fallback_i32.fixed b/tests/ui/default_numeric_fallback_i32.fixed index 55451cf2f7d0..3f4994f0453b 100644 --- a/tests/ui/default_numeric_fallback_i32.fixed +++ b/tests/ui/default_numeric_fallback_i32.fixed @@ -33,6 +33,8 @@ mod basic_expr { let x: [i32; 3] = [1, 2, 3]; let x: (i32, i32) = if true { (1, 2) } else { (3, 4) }; let x: _ = 1; + let x: u64 = 1; + const CONST_X: i8 = 1; } } @@ -59,6 +61,14 @@ mod nested_local { // Should NOT lint this because this literal is bound to `_` of outer `Local`. 2 }; + + const CONST_X: i32 = { + // Should lint this because this literal is not bound to any types. + let y = 1_i32; + + // Should NOT lint this because this literal is bound to `_` of outer `Local`. + 1 + }; } } diff --git a/tests/ui/default_numeric_fallback_i32.rs b/tests/ui/default_numeric_fallback_i32.rs index 62d72f2febaa..2df0e09787f9 100644 --- a/tests/ui/default_numeric_fallback_i32.rs +++ b/tests/ui/default_numeric_fallback_i32.rs @@ -33,6 +33,8 @@ mod basic_expr { let x: [i32; 3] = [1, 2, 3]; let x: (i32, i32) = if true { (1, 2) } else { (3, 4) }; let x: _ = 1; + let x: u64 = 1; + const CONST_X: i8 = 1; } } @@ -59,6 +61,14 @@ mod nested_local { // Should NOT lint this because this literal is bound to `_` of outer `Local`. 2 }; + + const CONST_X: i32 = { + // Should lint this because this literal is not bound to any types. + let y = 1; + + // Should NOT lint this because this literal is bound to `_` of outer `Local`. + 1 + }; } } diff --git a/tests/ui/default_numeric_fallback_i32.stderr b/tests/ui/default_numeric_fallback_i32.stderr index f7c5e724c403..6f219c3fc2b0 100644 --- a/tests/ui/default_numeric_fallback_i32.stderr +++ b/tests/ui/default_numeric_fallback_i32.stderr @@ -73,79 +73,85 @@ LL | _ => 2, | ^ help: consider adding suffix: `2_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:43:21 + --> $DIR/default_numeric_fallback_i32.rs:45:21 | LL | let y = 1; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:51:21 + --> $DIR/default_numeric_fallback_i32.rs:53:21 | LL | let y = 1; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:57:21 + --> $DIR/default_numeric_fallback_i32.rs:59:21 | LL | let y = 1; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:69:9 + --> $DIR/default_numeric_fallback_i32.rs:67:21 + | +LL | let y = 1; + | ^ help: consider adding suffix: `1_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback_i32.rs:79:9 | LL | 1 | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:75:27 + --> $DIR/default_numeric_fallback_i32.rs:85:27 | LL | let f = || -> _ { 1 }; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:79:29 + --> $DIR/default_numeric_fallback_i32.rs:89:29 | LL | let f = || -> i32 { 1 }; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:93:21 + --> $DIR/default_numeric_fallback_i32.rs:103:21 | LL | generic_arg(1); | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:96:32 + --> $DIR/default_numeric_fallback_i32.rs:106:32 | LL | let x: _ = generic_arg(1); | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:114:28 + --> $DIR/default_numeric_fallback_i32.rs:124:28 | LL | GenericStruct { x: 1 }; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:117:36 + --> $DIR/default_numeric_fallback_i32.rs:127:36 | LL | let _ = GenericStruct { x: 1 }; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:135:24 + --> $DIR/default_numeric_fallback_i32.rs:145:24 | LL | GenericEnum::X(1); | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:155:23 + --> $DIR/default_numeric_fallback_i32.rs:165:23 | LL | s.generic_arg(1); | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:162:21 + --> $DIR/default_numeric_fallback_i32.rs:172:21 | LL | let x = 22; | ^^ help: consider adding suffix: `22_i32` @@ -155,5 +161,5 @@ LL | internal_macro!(); | = note: this error originates in the macro `internal_macro` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 25 previous errors +error: aborting due to 26 previous errors From 36b2685977bdd731a0ef28e12bf8ef0334507d9e Mon Sep 17 00:00:00 2001 From: kraktus Date: Wed, 12 Oct 2022 23:00:52 +0200 Subject: [PATCH 2/3] refactor `default_numeric_fallback` We only need to store if the literal binding has an explicit type bound or not --- clippy_lints/src/default_numeric_fallback.rs | 45 ++++++++------------ 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 8b5c9d25dc85..199f8e10e549 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback { struct NumericFallbackVisitor<'a, 'tcx> { /// Stack manages type bound of exprs. The top element holds current expr type. - ty_bounds: Vec>, + ty_bounds: Vec, cx: &'a LateContext<'tcx>, } @@ -76,9 +76,9 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> { fn new(cx: &'a LateContext<'tcx>, is_parent_const: bool) -> Self { Self { ty_bounds: vec![if is_parent_const { - TyBound::Any + ExplicitTyBound(true) } else { - TyBound::Nothing + ExplicitTyBound(false) }], cx, } @@ -88,10 +88,10 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> { fn check_lit(&self, lit: &Lit, lit_ty: Ty<'tcx>, emit_hir_id: HirId) { if_chain! { if !in_external_macro(self.cx.sess(), lit.span); - if let Some(ty_bound) = self.ty_bounds.last(); + if let Some(explicit_ty_bounds) = self.ty_bounds.last(); if matches!(lit.node, LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed)); - if !ty_bound.is_numeric(); + if !explicit_ty_bounds.0; then { let (suffix, is_float) = match lit_ty.kind() { ty::Int(IntTy::I32) => ("i32", false), @@ -132,7 +132,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { if let Some(fn_sig) = fn_sig_opt(self.cx, func.hir_id) { for (expr, bound) in iter::zip(*args, fn_sig.skip_binder().inputs()) { // Push found arg type, then visit arg. - self.ty_bounds.push(TyBound::Ty(*bound)); + self.ty_bounds.push((*bound).into()); self.visit_expr(expr); self.ty_bounds.pop(); } @@ -144,7 +144,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) { let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder(); for (expr, bound) in iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) { - self.ty_bounds.push(TyBound::Ty(*bound)); + self.ty_bounds.push((*bound).into()); self.visit_expr(expr); self.ty_bounds.pop(); } @@ -178,7 +178,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { // Visit base with no bound. if let Some(base) = base { - self.ty_bounds.push(TyBound::Nothing); + self.ty_bounds.push(ExplicitTyBound(false)); self.visit_expr(base); self.ty_bounds.pop(); } @@ -201,9 +201,10 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) { match stmt.kind { - StmtKind::Local(local) if local.ty.is_some() => self.ty_bounds.push(TyBound::Any), + // we cannot check the exact type since it's a hir::Ty which does not implement `is_numeric` + StmtKind::Local(local) => self.ty_bounds.push(ExplicitTyBound(local.ty.is_some())), - _ => self.ty_bounds.push(TyBound::Nothing), + _ => self.ty_bounds.push(ExplicitTyBound(false)), } walk_stmt(self, stmt); @@ -221,28 +222,18 @@ fn fn_sig_opt<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option { - Any, - Ty(Ty<'tcx>), - Nothing, -} +struct ExplicitTyBound(pub bool); -impl<'tcx> TyBound<'tcx> { - fn is_numeric(self) -> bool { - match self { - TyBound::Any => true, - TyBound::Ty(t) => t.is_numeric(), - TyBound::Nothing => false, - } +impl<'tcx> From> for ExplicitTyBound { + fn from(v: Ty<'tcx>) -> Self { + Self(v.is_numeric()) } } -impl<'tcx> From>> for TyBound<'tcx> { +impl<'tcx> From>> for ExplicitTyBound { fn from(v: Option>) -> Self { - match v { - Some(t) => TyBound::Ty(t), - None => TyBound::Nothing, - } + Self(v.map_or(false, Ty::is_numeric)) } } From d38175f27188274bf5d6c1e433907bc50281c616 Mon Sep 17 00:00:00 2001 From: kraktus Date: Sat, 15 Oct 2022 14:57:08 +0200 Subject: [PATCH 3/3] `explicit_ty_bound` code golf --- clippy_lints/src/default_numeric_fallback.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 199f8e10e549..03460689e19a 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -88,10 +88,9 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> { fn check_lit(&self, lit: &Lit, lit_ty: Ty<'tcx>, emit_hir_id: HirId) { if_chain! { if !in_external_macro(self.cx.sess(), lit.span); - if let Some(explicit_ty_bounds) = self.ty_bounds.last(); + if matches!(self.ty_bounds.last(), Some(ExplicitTyBound(false))); if matches!(lit.node, LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed)); - if !explicit_ty_bounds.0; then { let (suffix, is_float) = match lit_ty.kind() { ty::Int(IntTy::I32) => ("i32", false),