about summary refs log tree commit diff
diff options
context:
space:
mode:
authorYoshitomo Nakanishi <yurayura.rounin.3@gmail.com>2021-02-16 11:20:51 +0900
committerYoshitomo Nakanishi <yurayura.rounin.3@gmail.com>2021-02-16 11:20:51 +0900
commit1f8ee3cc19f9259eea5e633affef968280d2ed1a (patch)
treef19191db10c5b3c78e6e3f962a33fa3c7dd22e00
parentfb91c76586a3a01fef6a8c49edb9e4598fbd138f (diff)
downloadrust-1f8ee3cc19f9259eea5e633affef968280d2ed1a.tar.gz
rust-1f8ee3cc19f9259eea5e633affef968280d2ed1a.zip
Handle struct ctor case
-rw-r--r--clippy_lints/src/default_numeric_fallback.rs53
-rw-r--r--tests/ui/default_numeric_fallback.rs37
-rw-r--r--tests/ui/default_numeric_fallback.stderr64
3 files changed, 145 insertions, 9 deletions
diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs
index d755112a178..33a577f336d 100644
--- a/clippy_lints/src/default_numeric_fallback.rs
+++ b/clippy_lints/src/default_numeric_fallback.rs
@@ -64,7 +64,7 @@ struct NumericFallbackVisitor<'a, 'tcx> {
 impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
     fn new(cx: &'a LateContext<'tcx>) -> Self {
         Self {
-            ty_bounds: Vec::new(),
+            ty_bounds: vec![TyBound::Nothing],
             cx,
         }
     }
@@ -121,6 +121,42 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
                 }
             },
 
+            ExprKind::Struct(qpath, fields, base) => {
+                if_chain! {
+                    if let Some(def_id) = self.cx.qpath_res(qpath, expr.hir_id).opt_def_id();
+                    let ty = self.cx.tcx.type_of(def_id);
+                    if let Some(adt_def) = ty.ty_adt_def();
+                    if adt_def.is_struct();
+                    if let Some(variant) = adt_def.variants.iter().next();
+                    then {
+                        let fields_def = &variant.fields;
+
+                        // Push field type then visit each field expr.
+                        for field in fields.iter() {
+                            let bound =
+                                fields_def
+                                    .iter()
+                                    .find_map(|f_def| {
+                                        if f_def.ident == field.ident
+                                            { Some(self.cx.tcx.type_of(f_def.did)) }
+                                        else { None }
+                                    });
+                            self.ty_bounds.push(bound.into());
+                            self.visit_expr(field.expr);
+                            self.ty_bounds.pop();
+                        }
+
+                        // Visit base with no bound.
+                        if let Some(base) = base {
+                            self.ty_bounds.push(TyBound::Nothing);
+                            self.visit_expr(base);
+                            self.ty_bounds.pop();
+                        }
+                        return;
+                    }
+                }
+            },
+
             ExprKind::Lit(lit) => {
                 let ty = self.cx.typeck_results().expr_ty(expr);
                 self.check_lit(lit, ty);
@@ -166,13 +202,13 @@ fn fn_sig_opt<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<PolyFnSig<'
 }
 
 #[derive(Debug, Clone, Copy)]
-enum TyBound<'ctx> {
+enum TyBound<'tcx> {
     Any,
-    Ty(Ty<'ctx>),
+    Ty(Ty<'tcx>),
     Nothing,
 }
 
-impl<'ctx> TyBound<'ctx> {
+impl<'tcx> TyBound<'tcx> {
     fn is_integral(self) -> bool {
         match self {
             TyBound::Any => true,
@@ -181,3 +217,12 @@ impl<'ctx> TyBound<'ctx> {
         }
     }
 }
+
+impl<'tcx> From<Option<Ty<'tcx>>> for TyBound<'tcx> {
+    fn from(v: Option<Ty<'tcx>>) -> Self {
+        match v {
+            Some(t) => TyBound::Ty(t),
+            None => TyBound::Nothing,
+        }
+    }
+}
diff --git a/tests/ui/default_numeric_fallback.rs b/tests/ui/default_numeric_fallback.rs
index c4881094469..0b3758952ac 100644
--- a/tests/ui/default_numeric_fallback.rs
+++ b/tests/ui/default_numeric_fallback.rs
@@ -39,6 +39,20 @@ mod nested_local {
             // Should NOT lint this because this literal is bound to `_` of outer `Local`.
             1
         };
+
+        let x: _ = if true {
+            // 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
+        } else {
+            // 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`.
+            2
+        };
     }
 }
 
@@ -46,7 +60,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.
-        23
+        1
     }
 
     fn test() {
@@ -77,6 +91,27 @@ mod function_calls {
     }
 }
 
+mod struct_ctor {
+    struct ConcreteStruct {
+        x: i32,
+    }
+
+    struct GenericStruct<T> {
+        x: T,
+    }
+
+    fn test() {
+        // Should NOT lint this because the field type is bound to a concrete type.
+        ConcreteStruct { x: 1 };
+
+        // Should lint this because the field type is inferred to `i32` and NOT bound to a concrete type.
+        GenericStruct { x: 1 };
+
+        // Should lint this because the field type is inferred to `i32` and NOT bound to a concrete type.
+        let _ = GenericStruct { x: 1 };
+    }
+}
+
 mod method_calls {
     struct StructForMethodCallTest {}
 
diff --git a/tests/ui/default_numeric_fallback.stderr b/tests/ui/default_numeric_fallback.stderr
index c71d05d7993..50fcdfb510e 100644
--- a/tests/ui/default_numeric_fallback.stderr
+++ b/tests/ui/default_numeric_fallback.stderr
@@ -112,7 +112,47 @@ LL |             let y = 1;
    = help: consider adding suffix to avoid default numeric fallback
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:73:21
+  --> $DIR/default_numeric_fallback.rs:45:21
+   |
+LL |             let y = 1;
+   |                     ^
+   |
+   = help: consider adding suffix to avoid default numeric fallback
+
+error: default numeric fallback might occur
+  --> $DIR/default_numeric_fallback.rs:51:21
+   |
+LL |             let y = 1;
+   |                     ^
+   |
+   = help: consider adding suffix to avoid default numeric fallback
+
+error: default numeric fallback might occur
+  --> $DIR/default_numeric_fallback.rs:63:9
+   |
+LL |         1
+   |         ^
+   |
+   = help: consider adding suffix to avoid default numeric fallback
+
+error: default numeric fallback might occur
+  --> $DIR/default_numeric_fallback.rs:69:27
+   |
+LL |         let f = || -> _ { 1 };
+   |                           ^
+   |
+   = help: consider adding suffix to avoid default numeric fallback
+
+error: default numeric fallback might occur
+  --> $DIR/default_numeric_fallback.rs:73:29
+   |
+LL |         let f = || -> i32 { 1 };
+   |                             ^
+   |
+   = help: consider adding suffix to avoid default numeric fallback
+
+error: default numeric fallback might occur
+  --> $DIR/default_numeric_fallback.rs:87:21
    |
 LL |         generic_arg(1);
    |                     ^
@@ -120,7 +160,7 @@ LL |         generic_arg(1);
    = help: consider adding suffix to avoid default numeric fallback
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:76:32
+  --> $DIR/default_numeric_fallback.rs:90:32
    |
 LL |         let x: _ = generic_arg(1);
    |                                ^
@@ -128,12 +168,28 @@ LL |         let x: _ = generic_arg(1);
    = help: consider adding suffix to avoid default numeric fallback
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:96:23
+  --> $DIR/default_numeric_fallback.rs:108:28
+   |
+LL |         GenericStruct { x: 1 };
+   |                            ^
+   |
+   = help: consider adding suffix to avoid default numeric fallback
+
+error: default numeric fallback might occur
+  --> $DIR/default_numeric_fallback.rs:111:36
+   |
+LL |         let _ = GenericStruct { x: 1 };
+   |                                    ^
+   |
+   = help: consider adding suffix to avoid default numeric fallback
+
+error: default numeric fallback might occur
+  --> $DIR/default_numeric_fallback.rs:131:23
    |
 LL |         s.generic_arg(1);
    |                       ^
    |
    = help: consider adding suffix to avoid default numeric fallback
 
-error: aborting due to 17 previous errors
+error: aborting due to 24 previous errors