Skip to content

Commit 4a2d09a

Browse files
committed
Auto merge of #6187 - geoffreycopin:master, r=ebroto
Lint unnecessary int-to-int and float-to-float casts This is an implementation of a lint that detects unnecessary casts of number literals, as discussed here: #6116 --- changelog: lint unnecessary as-casts of literals when they could be written using literal syntax.
2 parents bf1c6f9 + d46edd9 commit 4a2d09a

File tree

6 files changed

+189
-44
lines changed

6 files changed

+189
-44
lines changed

clippy_lints/src/types.rs

+54-12
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_hir as hir;
1111
use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor};
1212
use rustc_hir::{
1313
BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem,
14-
ImplItemKind, Item, ItemKind, Lifetime, Local, MatchSource, MutTy, Mutability, Node, QPath, Stmt, StmtKind,
14+
ImplItemKind, Item, ItemKind, Lifetime, Lit, Local, MatchSource, MutTy, Mutability, Node, QPath, Stmt, StmtKind,
1515
TraitFn, TraitItem, TraitItemKind, TyKind, UnOp,
1616
};
1717
use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -1224,7 +1224,8 @@ declare_clippy_lint! {
12241224
}
12251225

12261226
declare_clippy_lint! {
1227-
/// **What it does:** Checks for casts to the same type.
1227+
/// **What it does:** Checks for casts to the same type, casts of int literals to integer types
1228+
/// and casts of float literals to float types.
12281229
///
12291230
/// **Why is this bad?** It's just unnecessary.
12301231
///
@@ -1233,6 +1234,14 @@ declare_clippy_lint! {
12331234
/// **Example:**
12341235
/// ```rust
12351236
/// let _ = 2i32 as i32;
1237+
/// let _ = 0.5 as f32;
1238+
/// ```
1239+
///
1240+
/// Better:
1241+
///
1242+
/// ```rust
1243+
/// let _ = 2_i32;
1244+
/// let _ = 0.5_f32;
12361245
/// ```
12371246
pub UNNECESSARY_CAST,
12381247
complexity,
@@ -1598,7 +1607,9 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
15981607
if let ExprKind::Cast(ref ex, _) = expr.kind {
15991608
let (cast_from, cast_to) = (cx.typeck_results().expr_ty(ex), cx.typeck_results().expr_ty(expr));
16001609
lint_fn_to_numeric_cast(cx, expr, ex, cast_from, cast_to);
1601-
if let ExprKind::Lit(ref lit) = ex.kind {
1610+
if let Some(lit) = get_numeric_literal(ex) {
1611+
let literal_str = snippet_opt(cx, ex.span).unwrap_or_default();
1612+
16021613
if_chain! {
16031614
if let LitKind::Int(n, _) = lit.node;
16041615
if let Some(src) = snippet_opt(cx, lit.span);
@@ -1608,19 +1619,19 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
16081619
let to_nbits = fp_ty_mantissa_nbits(cast_to);
16091620
if from_nbits != 0 && to_nbits != 0 && from_nbits <= to_nbits && num_lit.is_decimal();
16101621
then {
1611-
span_lint_and_sugg(
1612-
cx,
1613-
UNNECESSARY_CAST,
1614-
expr.span,
1615-
&format!("casting integer literal to `{}` is unnecessary", cast_to),
1616-
"try",
1617-
format!("{}_{}", n, cast_to),
1618-
Applicability::MachineApplicable,
1619-
);
1622+
let literal_str = if is_unary_neg(ex) { format!("-{}", num_lit.integer) } else { num_lit.integer.into() };
1623+
show_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
16201624
return;
16211625
}
16221626
}
1627+
16231628
match lit.node {
1629+
LitKind::Int(_, LitIntType::Unsuffixed) if cast_to.is_integral() => {
1630+
show_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
1631+
},
1632+
LitKind::Float(_, LitFloatType::Unsuffixed) if cast_to.is_floating_point() => {
1633+
show_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
1634+
},
16241635
LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) => {},
16251636
_ => {
16261637
if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) {
@@ -1646,6 +1657,37 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
16461657
}
16471658
}
16481659

1660+
fn is_unary_neg(expr: &Expr<'_>) -> bool {
1661+
matches!(expr.kind, ExprKind::Unary(UnOp::UnNeg, _))
1662+
}
1663+
1664+
fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<&'e Lit> {
1665+
match expr.kind {
1666+
ExprKind::Lit(ref lit) => Some(lit),
1667+
ExprKind::Unary(UnOp::UnNeg, e) => {
1668+
if let ExprKind::Lit(ref lit) = e.kind {
1669+
Some(lit)
1670+
} else {
1671+
None
1672+
}
1673+
},
1674+
_ => None,
1675+
}
1676+
}
1677+
1678+
fn show_unnecessary_cast(cx: &LateContext<'_>, expr: &Expr<'_>, literal_str: &str, cast_from: Ty<'_>, cast_to: Ty<'_>) {
1679+
let literal_kind_name = if cast_from.is_integral() { "integer" } else { "float" };
1680+
span_lint_and_sugg(
1681+
cx,
1682+
UNNECESSARY_CAST,
1683+
expr.span,
1684+
&format!("casting {} literal to `{}` is unnecessary", literal_kind_name, cast_to),
1685+
"try",
1686+
format!("{}_{}", literal_str, cast_to),
1687+
Applicability::MachineApplicable,
1688+
);
1689+
}
1690+
16491691
fn lint_numeric_casts<'tcx>(
16501692
cx: &LateContext<'tcx>,
16511693
expr: &Expr<'tcx>,

tests/ui/eq_op.rs

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#[allow(clippy::no_effect, unused_variables, clippy::unnecessary_operation, clippy::short_circuit_statement)]
77
#[allow(clippy::nonminimal_bool)]
88
#[allow(unused)]
9+
#[allow(clippy::unnecessary_cast)]
910
fn main() {
1011
// simple values and comparisons
1112
1 == 1;

tests/ui/eq_op.stderr

+27-27
Original file line numberDiff line numberDiff line change
@@ -1,163 +1,163 @@
11
error: equal expressions as operands to `==`
2-
--> $DIR/eq_op.rs:11:5
2+
--> $DIR/eq_op.rs:12:5
33
|
44
LL | 1 == 1;
55
| ^^^^^^
66
|
77
= note: `-D clippy::eq-op` implied by `-D warnings`
88

99
error: equal expressions as operands to `==`
10-
--> $DIR/eq_op.rs:12:5
10+
--> $DIR/eq_op.rs:13:5
1111
|
1212
LL | "no" == "no";
1313
| ^^^^^^^^^^^^
1414

1515
error: equal expressions as operands to `!=`
16-
--> $DIR/eq_op.rs:14:5
16+
--> $DIR/eq_op.rs:15:5
1717
|
1818
LL | false != false;
1919
| ^^^^^^^^^^^^^^
2020

2121
error: equal expressions as operands to `<`
22-
--> $DIR/eq_op.rs:15:5
22+
--> $DIR/eq_op.rs:16:5
2323
|
2424
LL | 1.5 < 1.5;
2525
| ^^^^^^^^^
2626

2727
error: equal expressions as operands to `>=`
28-
--> $DIR/eq_op.rs:16:5
28+
--> $DIR/eq_op.rs:17:5
2929
|
3030
LL | 1u64 >= 1u64;
3131
| ^^^^^^^^^^^^
3232

3333
error: equal expressions as operands to `&`
34-
--> $DIR/eq_op.rs:19:5
34+
--> $DIR/eq_op.rs:20:5
3535
|
3636
LL | (1 as u64) & (1 as u64);
3737
| ^^^^^^^^^^^^^^^^^^^^^^^
3838

3939
error: equal expressions as operands to `^`
40-
--> $DIR/eq_op.rs:20:5
40+
--> $DIR/eq_op.rs:21:5
4141
|
4242
LL | 1 ^ ((((((1))))));
4343
| ^^^^^^^^^^^^^^^^^
4444

4545
error: equal expressions as operands to `<`
46-
--> $DIR/eq_op.rs:23:5
46+
--> $DIR/eq_op.rs:24:5
4747
|
4848
LL | (-(2) < -(2));
4949
| ^^^^^^^^^^^^^
5050

5151
error: equal expressions as operands to `==`
52-
--> $DIR/eq_op.rs:24:5
52+
--> $DIR/eq_op.rs:25:5
5353
|
5454
LL | ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
5555
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5656

5757
error: equal expressions as operands to `&`
58-
--> $DIR/eq_op.rs:24:6
58+
--> $DIR/eq_op.rs:25:6
5959
|
6060
LL | ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
6161
| ^^^^^^^^^^^^^^^^^
6262

6363
error: equal expressions as operands to `&`
64-
--> $DIR/eq_op.rs:24:27
64+
--> $DIR/eq_op.rs:25:27
6565
|
6666
LL | ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
6767
| ^^^^^^^^^^^^^^^^^
6868

6969
error: equal expressions as operands to `==`
70-
--> $DIR/eq_op.rs:25:5
70+
--> $DIR/eq_op.rs:26:5
7171
|
7272
LL | (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4;
7373
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7474

7575
error: equal expressions as operands to `!=`
76-
--> $DIR/eq_op.rs:28:5
76+
--> $DIR/eq_op.rs:29:5
7777
|
7878
LL | ([1] != [1]);
7979
| ^^^^^^^^^^^^
8080

8181
error: equal expressions as operands to `!=`
82-
--> $DIR/eq_op.rs:29:5
82+
--> $DIR/eq_op.rs:30:5
8383
|
8484
LL | ((1, 2) != (1, 2));
8585
| ^^^^^^^^^^^^^^^^^^
8686

8787
error: equal expressions as operands to `==`
88-
--> $DIR/eq_op.rs:33:5
88+
--> $DIR/eq_op.rs:34:5
8989
|
9090
LL | 1 + 1 == 2;
9191
| ^^^^^^^^^^
9292

9393
error: equal expressions as operands to `==`
94-
--> $DIR/eq_op.rs:34:5
94+
--> $DIR/eq_op.rs:35:5
9595
|
9696
LL | 1 - 1 == 0;
9797
| ^^^^^^^^^^
9898

9999
error: equal expressions as operands to `-`
100-
--> $DIR/eq_op.rs:34:5
100+
--> $DIR/eq_op.rs:35:5
101101
|
102102
LL | 1 - 1 == 0;
103103
| ^^^^^
104104

105105
error: equal expressions as operands to `-`
106-
--> $DIR/eq_op.rs:36:5
106+
--> $DIR/eq_op.rs:37:5
107107
|
108108
LL | 1 - 1;
109109
| ^^^^^
110110

111111
error: equal expressions as operands to `/`
112-
--> $DIR/eq_op.rs:37:5
112+
--> $DIR/eq_op.rs:38:5
113113
|
114114
LL | 1 / 1;
115115
| ^^^^^
116116

117117
error: equal expressions as operands to `&&`
118-
--> $DIR/eq_op.rs:38:5
118+
--> $DIR/eq_op.rs:39:5
119119
|
120120
LL | true && true;
121121
| ^^^^^^^^^^^^
122122

123123
error: equal expressions as operands to `||`
124-
--> $DIR/eq_op.rs:40:5
124+
--> $DIR/eq_op.rs:41:5
125125
|
126126
LL | true || true;
127127
| ^^^^^^^^^^^^
128128

129129
error: equal expressions as operands to `&&`
130-
--> $DIR/eq_op.rs:46:5
130+
--> $DIR/eq_op.rs:47:5
131131
|
132132
LL | a == b && b == a;
133133
| ^^^^^^^^^^^^^^^^
134134

135135
error: equal expressions as operands to `&&`
136-
--> $DIR/eq_op.rs:47:5
136+
--> $DIR/eq_op.rs:48:5
137137
|
138138
LL | a != b && b != a;
139139
| ^^^^^^^^^^^^^^^^
140140

141141
error: equal expressions as operands to `&&`
142-
--> $DIR/eq_op.rs:48:5
142+
--> $DIR/eq_op.rs:49:5
143143
|
144144
LL | a < b && b > a;
145145
| ^^^^^^^^^^^^^^
146146

147147
error: equal expressions as operands to `&&`
148-
--> $DIR/eq_op.rs:49:5
148+
--> $DIR/eq_op.rs:50:5
149149
|
150150
LL | a <= b && b >= a;
151151
| ^^^^^^^^^^^^^^^^
152152

153153
error: equal expressions as operands to `==`
154-
--> $DIR/eq_op.rs:52:5
154+
--> $DIR/eq_op.rs:53:5
155155
|
156156
LL | a == a;
157157
| ^^^^^^
158158

159159
error: equal expressions as operands to `/`
160-
--> $DIR/eq_op.rs:62:20
160+
--> $DIR/eq_op.rs:63:20
161161
|
162162
LL | const D: u32 = A / A;
163163
| ^^^^^

tests/ui/unnecessary_cast_fixable.fixed

+17-2
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,31 @@ fn main() {
88
100_f32;
99
100_f64;
1010
100_f64;
11+
let _ = -100_f32;
12+
let _ = -100_f64;
13+
let _ = -100_f64;
1114
// Should not trigger
1215
#[rustfmt::skip]
1316
let v = vec!(1);
1417
&v as &[i32];
15-
1.0 as f64;
16-
1 as u64;
1718
0x10 as f32;
1819
0o10 as f32;
1920
0b10 as f32;
2021
0x11 as f64;
2122
0o11 as f64;
2223
0b11 as f64;
24+
25+
1_u32;
26+
0x10_i32;
27+
0b10_usize;
28+
0o73_u16;
29+
1_000_000_000_u32;
30+
31+
1.0_f64;
32+
0.5_f32;
33+
34+
1.0 as u16;
35+
36+
let _ = -1_i32;
37+
let _ = -1.0_f32;
2338
}

tests/ui/unnecessary_cast_fixable.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,31 @@ fn main() {
88
100 as f32;
99
100 as f64;
1010
100_i32 as f64;
11+
let _ = -100 as f32;
12+
let _ = -100 as f64;
13+
let _ = -100_i32 as f64;
1114
// Should not trigger
1215
#[rustfmt::skip]
1316
let v = vec!(1);
1417
&v as &[i32];
15-
1.0 as f64;
16-
1 as u64;
1718
0x10 as f32;
1819
0o10 as f32;
1920
0b10 as f32;
2021
0x11 as f64;
2122
0o11 as f64;
2223
0b11 as f64;
24+
25+
1 as u32;
26+
0x10 as i32;
27+
0b10 as usize;
28+
0o73 as u16;
29+
1_000_000_000 as u32;
30+
31+
1.0 as f64;
32+
0.5 as f32;
33+
34+
1.0 as u16;
35+
36+
let _ = -1 as i32;
37+
let _ = -1.0 as f32;
2338
}

0 commit comments

Comments
 (0)