Skip to content

Commit 1f8ee3c

Browse files
committed
Handle struct ctor case
1 parent fb91c76 commit 1f8ee3c

File tree

3 files changed

+145
-9
lines changed

3 files changed

+145
-9
lines changed

clippy_lints/src/default_numeric_fallback.rs

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ struct NumericFallbackVisitor<'a, 'tcx> {
6464
impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
6565
fn new(cx: &'a LateContext<'tcx>) -> Self {
6666
Self {
67-
ty_bounds: Vec::new(),
67+
ty_bounds: vec![TyBound::Nothing],
6868
cx,
6969
}
7070
}
@@ -121,6 +121,42 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
121121
}
122122
},
123123

124+
ExprKind::Struct(qpath, fields, base) => {
125+
if_chain! {
126+
if let Some(def_id) = self.cx.qpath_res(qpath, expr.hir_id).opt_def_id();
127+
let ty = self.cx.tcx.type_of(def_id);
128+
if let Some(adt_def) = ty.ty_adt_def();
129+
if adt_def.is_struct();
130+
if let Some(variant) = adt_def.variants.iter().next();
131+
then {
132+
let fields_def = &variant.fields;
133+
134+
// Push field type then visit each field expr.
135+
for field in fields.iter() {
136+
let bound =
137+
fields_def
138+
.iter()
139+
.find_map(|f_def| {
140+
if f_def.ident == field.ident
141+
{ Some(self.cx.tcx.type_of(f_def.did)) }
142+
else { None }
143+
});
144+
self.ty_bounds.push(bound.into());
145+
self.visit_expr(field.expr);
146+
self.ty_bounds.pop();
147+
}
148+
149+
// Visit base with no bound.
150+
if let Some(base) = base {
151+
self.ty_bounds.push(TyBound::Nothing);
152+
self.visit_expr(base);
153+
self.ty_bounds.pop();
154+
}
155+
return;
156+
}
157+
}
158+
},
159+
124160
ExprKind::Lit(lit) => {
125161
let ty = self.cx.typeck_results().expr_ty(expr);
126162
self.check_lit(lit, ty);
@@ -166,13 +202,13 @@ fn fn_sig_opt<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<PolyFnSig<'
166202
}
167203

168204
#[derive(Debug, Clone, Copy)]
169-
enum TyBound<'ctx> {
205+
enum TyBound<'tcx> {
170206
Any,
171-
Ty(Ty<'ctx>),
207+
Ty(Ty<'tcx>),
172208
Nothing,
173209
}
174210

175-
impl<'ctx> TyBound<'ctx> {
211+
impl<'tcx> TyBound<'tcx> {
176212
fn is_integral(self) -> bool {
177213
match self {
178214
TyBound::Any => true,
@@ -181,3 +217,12 @@ impl<'ctx> TyBound<'ctx> {
181217
}
182218
}
183219
}
220+
221+
impl<'tcx> From<Option<Ty<'tcx>>> for TyBound<'tcx> {
222+
fn from(v: Option<Ty<'tcx>>) -> Self {
223+
match v {
224+
Some(t) => TyBound::Ty(t),
225+
None => TyBound::Nothing,
226+
}
227+
}
228+
}

tests/ui/default_numeric_fallback.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,28 @@ mod nested_local {
3939
// Should NOT lint this because this literal is bound to `_` of outer `Local`.
4040
1
4141
};
42+
43+
let x: _ = if true {
44+
// Should lint this because this literal is not bound to any types.
45+
let y = 1;
46+
47+
// Should NOT lint this because this literal is bound to `_` of outer `Local`.
48+
1
49+
} else {
50+
// Should lint this because this literal is not bound to any types.
51+
let y = 1;
52+
53+
// Should NOT lint this because this literal is bound to `_` of outer `Local`.
54+
2
55+
};
4256
}
4357
}
4458

4559
mod function_def {
4660
fn ret_i32() -> i32 {
4761
// Even though the output type is specified,
4862
// this unsuffixed literal is linted to reduce heuristics and keep codebase simple.
49-
23
63+
1
5064
}
5165

5266
fn test() {
@@ -77,6 +91,27 @@ mod function_calls {
7791
}
7892
}
7993

94+
mod struct_ctor {
95+
struct ConcreteStruct {
96+
x: i32,
97+
}
98+
99+
struct GenericStruct<T> {
100+
x: T,
101+
}
102+
103+
fn test() {
104+
// Should NOT lint this because the field type is bound to a concrete type.
105+
ConcreteStruct { x: 1 };
106+
107+
// Should lint this because the field type is inferred to `i32` and NOT bound to a concrete type.
108+
GenericStruct { x: 1 };
109+
110+
// Should lint this because the field type is inferred to `i32` and NOT bound to a concrete type.
111+
let _ = GenericStruct { x: 1 };
112+
}
113+
}
114+
80115
mod method_calls {
81116
struct StructForMethodCallTest {}
82117

tests/ui/default_numeric_fallback.stderr

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,28 +112,84 @@ LL | let y = 1;
112112
= help: consider adding suffix to avoid default numeric fallback
113113

114114
error: default numeric fallback might occur
115-
--> $DIR/default_numeric_fallback.rs:73:21
115+
--> $DIR/default_numeric_fallback.rs:45:21
116+
|
117+
LL | let y = 1;
118+
| ^
119+
|
120+
= help: consider adding suffix to avoid default numeric fallback
121+
122+
error: default numeric fallback might occur
123+
--> $DIR/default_numeric_fallback.rs:51:21
124+
|
125+
LL | let y = 1;
126+
| ^
127+
|
128+
= help: consider adding suffix to avoid default numeric fallback
129+
130+
error: default numeric fallback might occur
131+
--> $DIR/default_numeric_fallback.rs:63:9
132+
|
133+
LL | 1
134+
| ^
135+
|
136+
= help: consider adding suffix to avoid default numeric fallback
137+
138+
error: default numeric fallback might occur
139+
--> $DIR/default_numeric_fallback.rs:69:27
140+
|
141+
LL | let f = || -> _ { 1 };
142+
| ^
143+
|
144+
= help: consider adding suffix to avoid default numeric fallback
145+
146+
error: default numeric fallback might occur
147+
--> $DIR/default_numeric_fallback.rs:73:29
148+
|
149+
LL | let f = || -> i32 { 1 };
150+
| ^
151+
|
152+
= help: consider adding suffix to avoid default numeric fallback
153+
154+
error: default numeric fallback might occur
155+
--> $DIR/default_numeric_fallback.rs:87:21
116156
|
117157
LL | generic_arg(1);
118158
| ^
119159
|
120160
= help: consider adding suffix to avoid default numeric fallback
121161

122162
error: default numeric fallback might occur
123-
--> $DIR/default_numeric_fallback.rs:76:32
163+
--> $DIR/default_numeric_fallback.rs:90:32
124164
|
125165
LL | let x: _ = generic_arg(1);
126166
| ^
127167
|
128168
= help: consider adding suffix to avoid default numeric fallback
129169

130170
error: default numeric fallback might occur
131-
--> $DIR/default_numeric_fallback.rs:96:23
171+
--> $DIR/default_numeric_fallback.rs:108:28
172+
|
173+
LL | GenericStruct { x: 1 };
174+
| ^
175+
|
176+
= help: consider adding suffix to avoid default numeric fallback
177+
178+
error: default numeric fallback might occur
179+
--> $DIR/default_numeric_fallback.rs:111:36
180+
|
181+
LL | let _ = GenericStruct { x: 1 };
182+
| ^
183+
|
184+
= help: consider adding suffix to avoid default numeric fallback
185+
186+
error: default numeric fallback might occur
187+
--> $DIR/default_numeric_fallback.rs:131:23
132188
|
133189
LL | s.generic_arg(1);
134190
| ^
135191
|
136192
= help: consider adding suffix to avoid default numeric fallback
137193

138-
error: aborting due to 17 previous errors
194+
error: aborting due to 24 previous errors
139195

0 commit comments

Comments
 (0)