diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 64a924a776a..712bc075650 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, walk_stmt, Visitor}; -use rustc_hir::{Body, Expr, ExprKind, HirId, ItemKind, Lit, Node, Stmt, StmtKind}; +use rustc_hir::{Block, Body, Expr, ExprKind, FnRetTy, HirId, ItemKind, Lit, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty}; @@ -122,13 +122,42 @@ fn check_lit(&self, lit: &Lit, lit_ty: Ty<'tcx>, emit_hir_id: HirId) { impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { match &expr.kind { + ExprKind::Block( + Block { + stmts, expr: Some(_), .. + }, + _, + ) => { + if let Some(parent) = self.cx.tcx.hir().find_parent(expr.hir_id) + && let Some(fn_sig) = parent.fn_sig() + && let FnRetTy::Return(_ty) = fn_sig.decl.output + { + // We cannot check the exact type since it's a `hir::Ty`` which does not implement `is_numeric` + self.ty_bounds.push(ExplicitTyBound(true)); + for stmt in *stmts { + self.visit_stmt(stmt); + } + self.ty_bounds.pop(); + // Ignore return expr since we know its type was inferred from return ty + return; + } + }, + + // Ignore return expr since we know its type was inferred from return ty + ExprKind::Ret(_) => return, + ExprKind::Call(func, args) => { 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((*bound).into()); - self.visit_expr(expr); - self.ty_bounds.pop(); + // If is from macro, try to use last bound type (typically pushed when visiting stmt), + // otherwise push found arg type, then visit arg, + if expr.span.from_expansion() { + self.visit_expr(expr); + } else { + self.ty_bounds.push((*bound).into()); + self.visit_expr(expr); + self.ty_bounds.pop(); + } } return; } @@ -137,7 +166,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { ExprKind::MethodCall(_, receiver, args, _) => { 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).instantiate_identity().skip_binder(); - for (expr, bound) in iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) { + for (expr, bound) in iter::zip(iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) { self.ty_bounds.push((*bound).into()); self.visit_expr(expr); self.ty_bounds.pop(); diff --git a/tests/ui/default_numeric_fallback_f64.fixed b/tests/ui/default_numeric_fallback_f64.fixed index 9072d233563..e62dc8b255e 100644 --- a/tests/ui/default_numeric_fallback_f64.fixed +++ b/tests/ui/default_numeric_fallback_f64.fixed @@ -75,7 +75,7 @@ mod function_def { fn ret_f64() -> f64 { // Even though the output type is specified, // this unsuffixed literal is linted to reduce heuristics and keep codebase simple. - 1.0_f64 + 1. } fn test() { diff --git a/tests/ui/default_numeric_fallback_f64.stderr b/tests/ui/default_numeric_fallback_f64.stderr index 7ea2e3e6819..e81aafdb3f3 100644 --- a/tests/ui/default_numeric_fallback_f64.stderr +++ b/tests/ui/default_numeric_fallback_f64.stderr @@ -85,12 +85,6 @@ error: default numeric fallback might occur 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:84:27 | @@ -147,5 +141,5 @@ LL | inline!(let x = 22.;); | = note: this error originates in the macro `__inline_mac_fn_internal` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 24 previous errors +error: aborting due to 23 previous errors diff --git a/tests/ui/default_numeric_fallback_i32.fixed b/tests/ui/default_numeric_fallback_i32.fixed index 920cd9f8f77..115cd30a6b3 100644 --- a/tests/ui/default_numeric_fallback_i32.fixed +++ b/tests/ui/default_numeric_fallback_i32.fixed @@ -76,7 +76,7 @@ mod function_def { fn ret_i32() -> i32 { // Even though the output type is specified, // this unsuffixed literal is linted to reduce heuristics and keep codebase simple. - 1_i32 + 1 } fn test() { @@ -186,4 +186,36 @@ fn check_expect_suppression() { let x = 21; } +mod type_already_infered { + // Should NOT lint if bound to return type + fn ret_i32() -> i32 { + 1 + } + + // Should NOT lint if bound to return type + fn ret_if_i32(b: bool) -> i32 { + if b { 100 } else { 0 } + } + + // Should NOT lint if bound to return type + fn ret_i32_tuple() -> (i32, i32) { + (0, 1) + } + + // Should NOT lint if bound to return type + fn ret_stmt(b: bool) -> (i32, i32) { + if b { + return (0, 1); + } + (0, 0) + } + + #[allow(clippy::useless_vec)] + fn vec_macro() { + // Should NOT lint in `vec!` call if the type was already stated + let data_i32: Vec = vec![1, 2, 3]; + let data_i32 = vec![1_i32, 2_i32, 3_i32]; + } +} + fn main() {} diff --git a/tests/ui/default_numeric_fallback_i32.rs b/tests/ui/default_numeric_fallback_i32.rs index bdb7b5f47bc..a4abfc11320 100644 --- a/tests/ui/default_numeric_fallback_i32.rs +++ b/tests/ui/default_numeric_fallback_i32.rs @@ -186,4 +186,36 @@ fn check_expect_suppression() { let x = 21; } +mod type_already_infered { + // Should NOT lint if bound to return type + fn ret_i32() -> i32 { + 1 + } + + // Should NOT lint if bound to return type + fn ret_if_i32(b: bool) -> i32 { + if b { 100 } else { 0 } + } + + // Should NOT lint if bound to return type + fn ret_i32_tuple() -> (i32, i32) { + (0, 1) + } + + // Should NOT lint if bound to return type + fn ret_stmt(b: bool) -> (i32, i32) { + if b { + return (0, 1); + } + (0, 0) + } + + #[allow(clippy::useless_vec)] + fn vec_macro() { + // Should NOT lint in `vec!` call if the type was already stated + let data_i32: Vec = vec![1, 2, 3]; + let data_i32 = vec![1, 2, 3]; + } +} + fn main() {} diff --git a/tests/ui/default_numeric_fallback_i32.stderr b/tests/ui/default_numeric_fallback_i32.stderr index b03b8b84c33..0da9b77f32e 100644 --- a/tests/ui/default_numeric_fallback_i32.stderr +++ b/tests/ui/default_numeric_fallback_i32.stderr @@ -97,12 +97,6 @@ error: default numeric fallback might occur 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:85:27 | @@ -159,5 +153,23 @@ LL | inline!(let x = 22;); | = note: this error originates in the macro `__inline_mac_fn_internal` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 26 previous errors +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback_i32.rs:217:29 + | +LL | let data_i32 = vec![1, 2, 3]; + | ^ help: consider adding suffix: `1_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback_i32.rs:217:32 + | +LL | let data_i32 = vec![1, 2, 3]; + | ^ help: consider adding suffix: `2_i32` + +error: default numeric fallback might occur + --> $DIR/default_numeric_fallback_i32.rs:217:35 + | +LL | let data_i32 = vec![1, 2, 3]; + | ^ help: consider adding suffix: `3_i32` + +error: aborting due to 28 previous errors