diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 64a924a776a6..712bc075650f 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -4,7 +4,7 @@ use clippy_utils::{get_parent_node, numeric_literal}; 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 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> { 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 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { 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 9072d2335634..00f0d7644340 100644 --- a/tests/ui/default_numeric_fallback_f64.fixed +++ b/tests/ui/default_numeric_fallback_f64.fixed @@ -73,9 +73,7 @@ mod nested_local { 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.rs b/tests/ui/default_numeric_fallback_f64.rs index 256b94f6c058..942cedac2753 100644 --- a/tests/ui/default_numeric_fallback_f64.rs +++ b/tests/ui/default_numeric_fallback_f64.rs @@ -73,8 +73,6 @@ mod nested_local { 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. } diff --git a/tests/ui/default_numeric_fallback_f64.stderr b/tests/ui/default_numeric_fallback_f64.stderr index 7ea2e3e68194..c95679c9eb81 100644 --- a/tests/ui/default_numeric_fallback_f64.stderr +++ b/tests/ui/default_numeric_fallback_f64.stderr @@ -86,66 +86,60 @@ 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 + --> $DIR/default_numeric_fallback_f64.rs:82:27 | LL | let f = || -> _ { 1. }; | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_f64.rs:88:29 + --> $DIR/default_numeric_fallback_f64.rs:86: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:102:21 + --> $DIR/default_numeric_fallback_f64.rs:100:21 | LL | generic_arg(1.); | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_f64.rs:105:32 + --> $DIR/default_numeric_fallback_f64.rs:103: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:123:28 + --> $DIR/default_numeric_fallback_f64.rs:121:28 | LL | GenericStruct { x: 1. }; | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_f64.rs:126:36 + --> $DIR/default_numeric_fallback_f64.rs:124: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:144:24 + --> $DIR/default_numeric_fallback_f64.rs:142:24 | LL | GenericEnum::X(1.); | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_f64.rs:164:23 + --> $DIR/default_numeric_fallback_f64.rs:162: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:174:25 + --> $DIR/default_numeric_fallback_f64.rs:172:25 | LL | inline!(let x = 22.;); | ^^^ help: consider adding suffix: `22.0_f64` | = 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 920cd9f8f771..9ef92d8f279a 100644 --- a/tests/ui/default_numeric_fallback_i32.fixed +++ b/tests/ui/default_numeric_fallback_i32.fixed @@ -74,9 +74,7 @@ mod nested_local { 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 +184,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 bdb7b5f47bca..4b54b8d84587 100644 --- a/tests/ui/default_numeric_fallback_i32.rs +++ b/tests/ui/default_numeric_fallback_i32.rs @@ -74,8 +74,6 @@ mod nested_local { 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 } @@ -186,4 +184,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 b03b8b84c332..7663977fb65a 100644 --- a/tests/ui/default_numeric_fallback_i32.stderr +++ b/tests/ui/default_numeric_fallback_i32.stderr @@ -98,66 +98,78 @@ 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 + --> $DIR/default_numeric_fallback_i32.rs:83:27 | LL | let f = || -> _ { 1 }; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:89:29 + --> $DIR/default_numeric_fallback_i32.rs:87:29 | LL | let f = || -> i32 { 1 }; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:103:21 + --> $DIR/default_numeric_fallback_i32.rs:101:21 | LL | generic_arg(1); | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:106:32 + --> $DIR/default_numeric_fallback_i32.rs:104: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:124:28 + --> $DIR/default_numeric_fallback_i32.rs:122:28 | LL | GenericStruct { x: 1 }; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:127:36 + --> $DIR/default_numeric_fallback_i32.rs:125:36 | LL | let _ = GenericStruct { x: 1 }; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:145:24 + --> $DIR/default_numeric_fallback_i32.rs:143:24 | LL | GenericEnum::X(1); | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:165:23 + --> $DIR/default_numeric_fallback_i32.rs:163:23 | LL | s.generic_arg(1); | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> $DIR/default_numeric_fallback_i32.rs:175:25 + --> $DIR/default_numeric_fallback_i32.rs:173:25 | LL | inline!(let x = 22;); | ^^ help: consider adding suffix: `22_i32` | = 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:215: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:215: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:215:35 + | +LL | let data_i32 = vec![1, 2, 3]; + | ^ help: consider adding suffix: `3_i32` + +error: aborting due to 28 previous errors