about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJ-ZhengLi <lizheng135@huawei.com>2023-12-13 11:09:08 +0800
committerJ-ZhengLi <lizheng135@huawei.com>2023-12-13 11:09:08 +0800
commit60c059114c3c1d2bcbe90c71f308b32f7cea1b07 (patch)
tree7efed6d21b0946fc0347a9d7aeb5f46eb39fdc5a
parent2793e8d103f7f977f8b672558c18f6ab1dc4a578 (diff)
downloadrust-60c059114c3c1d2bcbe90c71f308b32f7cea1b07.tar.gz
rust-60c059114c3c1d2bcbe90c71f308b32f7cea1b07.zip
[`default_numeric_fallback`]: don't lint on return and macro calls with stated type
-rw-r--r--clippy_lints/src/default_numeric_fallback.rs41
-rw-r--r--tests/ui/default_numeric_fallback_f64.fixed2
-rw-r--r--tests/ui/default_numeric_fallback_f64.stderr8
-rw-r--r--tests/ui/default_numeric_fallback_i32.fixed34
-rw-r--r--tests/ui/default_numeric_fallback_i32.rs32
-rw-r--r--tests/ui/default_numeric_fallback_i32.stderr26
6 files changed, 121 insertions, 22 deletions
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 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 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
@@ -86,12 +86,6 @@ 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
    |
 LL |         let f = || -> _ { 1. };
@@ -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<i32> = 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<i32> = 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
@@ -98,12 +98,6 @@ 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
    |
 LL |         let f = || -> _ { 1 };
@@ -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