Skip to content

Commit e2fdeec

Browse files
committed
Auto merge of rust-lang#5677 - lzutao:checked_conv, r=matthiaskrgr
Fix false negative of `checked_conversion` lint Closes rust-lang#5675 changelog: none
2 parents 6c833df + b39fd5f commit e2fdeec

File tree

5 files changed

+188
-200
lines changed

5 files changed

+188
-200
lines changed

clippy_lints/src/checked_conversions.rs

+39-39
Original file line numberDiff line numberDiff line change
@@ -58,24 +58,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CheckedConversions {
5858
}
5959
};
6060

61-
if_chain! {
62-
if let Some(cv) = result;
63-
if let Some(to_type) = cv.to_type;
64-
65-
then {
61+
if let Some(cv) = result {
62+
if let Some(to_type) = cv.to_type {
6663
let mut applicability = Applicability::MachineApplicable;
67-
let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut
68-
applicability);
64+
let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut applicability);
6965
span_lint_and_sugg(
7066
cx,
7167
CHECKED_CONVERSIONS,
7268
item.span,
7369
"Checked cast can be simplified.",
7470
"try",
75-
format!("{}::try_from({}).is_ok()",
76-
to_type,
77-
snippet),
78-
applicability
71+
format!("{}::try_from({}).is_ok()", to_type, snippet),
72+
applicability,
7973
);
8074
}
8175
}
@@ -184,7 +178,7 @@ fn check_upper_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
184178
if_chain! {
185179
if let ExprKind::Binary(ref op, ref left, ref right) = &expr.kind;
186180
if let Some((candidate, check)) = normalize_le_ge(op, left, right);
187-
if let Some((from, to)) = get_types_from_cast(check, MAX_VALUE, INTS);
181+
if let Some((from, to)) = get_types_from_cast(check, INTS, "max_value", "MAX");
188182

189183
then {
190184
Conversion::try_new(candidate, from, to)
@@ -224,18 +218,24 @@ fn check_lower_bound_zero<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> O
224218

225219
/// Check for `expr >= (to_type::MIN as from_type)`
226220
fn check_lower_bound_min<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Option<Conversion<'a>> {
227-
if let Some((from, to)) = get_types_from_cast(check, MIN_VALUE, SINTS) {
221+
if let Some((from, to)) = get_types_from_cast(check, SINTS, "min_value", "MIN") {
228222
Conversion::try_new(candidate, from, to)
229223
} else {
230224
None
231225
}
232226
}
233227

234228
/// Tries to extract the from- and to-type from a cast expression
235-
fn get_types_from_cast<'a>(expr: &'a Expr<'_>, func: &'a str, types: &'a [&str]) -> Option<(&'a str, &'a str)> {
236-
// `to_type::maxmin_value() as from_type`
229+
fn get_types_from_cast<'a>(
230+
expr: &'a Expr<'_>,
231+
types: &'a [&str],
232+
func: &'a str,
233+
assoc_const: &'a str,
234+
) -> Option<(&'a str, &'a str)> {
235+
// `to_type::max_value() as from_type`
236+
// or `to_type::MAX as from_type`
237237
let call_from_cast: Option<(&Expr<'_>, &str)> = if_chain! {
238-
// to_type::maxmin_value(), from_type
238+
// to_type::max_value(), from_type
239239
if let ExprKind::Cast(ref limit, ref from_type) = &expr.kind;
240240
if let TyKind::Path(ref from_type_path) = &from_type.kind;
241241
if let Some(from_sym) = int_ty_to_sym(from_type_path);
@@ -247,17 +247,17 @@ fn get_types_from_cast<'a>(expr: &'a Expr<'_>, func: &'a str, types: &'a [&str])
247247
}
248248
};
249249

250-
// `from_type::from(to_type::maxmin_value())`
250+
// `from_type::from(to_type::max_value())`
251251
let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| {
252252
if_chain! {
253-
// `from_type::from, to_type::maxmin_value()`
253+
// `from_type::from, to_type::max_value()`
254254
if let ExprKind::Call(ref from_func, ref args) = &expr.kind;
255-
// `to_type::maxmin_value()`
255+
// `to_type::max_value()`
256256
if args.len() == 1;
257257
if let limit = &args[0];
258258
// `from_type::from`
259259
if let ExprKind::Path(ref path) = &from_func.kind;
260-
if let Some(from_sym) = get_implementing_type(path, INTS, FROM);
260+
if let Some(from_sym) = get_implementing_type(path, INTS, "from");
261261

262262
then {
263263
Some((limit, from_sym))
@@ -268,22 +268,26 @@ fn get_types_from_cast<'a>(expr: &'a Expr<'_>, func: &'a str, types: &'a [&str])
268268
});
269269

270270
if let Some((limit, from_type)) = limit_from {
271-
if_chain! {
272-
if let ExprKind::Call(ref fun_name, _) = &limit.kind;
273-
// `to_type, maxmin_value`
274-
if let ExprKind::Path(ref path) = &fun_name.kind;
275-
// `to_type`
276-
if let Some(to_type) = get_implementing_type(path, types, func);
277-
278-
then {
279-
Some((from_type, to_type))
280-
} else {
281-
None
282-
}
271+
match limit.kind {
272+
// `from_type::from(_)`
273+
ExprKind::Call(path, _) => {
274+
if let ExprKind::Path(ref path) = path.kind {
275+
// `to_type`
276+
if let Some(to_type) = get_implementing_type(path, types, func) {
277+
return Some((from_type, to_type));
278+
}
279+
}
280+
},
281+
// `to_type::MAX`
282+
ExprKind::Path(ref path) => {
283+
if let Some(to_type) = get_implementing_type(path, types, assoc_const) {
284+
return Some((from_type, to_type));
285+
}
286+
},
287+
_ => {},
283288
}
284-
} else {
285-
None
286-
}
289+
};
290+
None
287291
}
288292

289293
/// Gets the type which implements the called function
@@ -336,10 +340,6 @@ fn normalize_le_ge<'a>(op: &BinOp, left: &'a Expr<'a>, right: &'a Expr<'a>) -> O
336340
}
337341

338342
// Constants
339-
const FROM: &str = "from";
340-
const MAX_VALUE: &str = "max_value";
341-
const MIN_VALUE: &str = "min_value";
342-
343343
const UINTS: &[&str] = &["u8", "u16", "u32", "u64", "usize"];
344344
const SINTS: &[&str] = &["i8", "i16", "i32", "i64", "isize"];
345345
const INTS: &[&str] = &["u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "isize"];

tests/ui/checked_conversions.fixed

+38-68
Original file line numberDiff line numberDiff line change
@@ -1,106 +1,76 @@
11
// run-rustfix
22

3+
#![allow(
4+
clippy::cast_lossless,
5+
// Int::max_value will be deprecated in the future
6+
deprecated,
7+
)]
38
#![warn(clippy::checked_conversions)]
4-
#![allow(clippy::cast_lossless)]
5-
#![allow(dead_code)]
9+
610
use std::convert::TryFrom;
711

812
// Positive tests
913

1014
// Signed to unsigned
1115

12-
fn i64_to_u32(value: i64) -> Option<u32> {
13-
if u32::try_from(value).is_ok() {
14-
Some(value as u32)
15-
} else {
16-
None
17-
}
16+
pub fn i64_to_u32(value: i64) {
17+
let _ = u32::try_from(value).is_ok();
18+
let _ = u32::try_from(value).is_ok();
1819
}
1920

20-
fn i64_to_u16(value: i64) -> Option<u16> {
21-
if u16::try_from(value).is_ok() {
22-
Some(value as u16)
23-
} else {
24-
None
25-
}
21+
pub fn i64_to_u16(value: i64) {
22+
let _ = u16::try_from(value).is_ok();
23+
let _ = u16::try_from(value).is_ok();
2624
}
2725

28-
fn isize_to_u8(value: isize) -> Option<u8> {
29-
if u8::try_from(value).is_ok() {
30-
Some(value as u8)
31-
} else {
32-
None
33-
}
26+
pub fn isize_to_u8(value: isize) {
27+
let _ = u8::try_from(value).is_ok();
28+
let _ = u8::try_from(value).is_ok();
3429
}
3530

3631
// Signed to signed
3732

38-
fn i64_to_i32(value: i64) -> Option<i32> {
39-
if i32::try_from(value).is_ok() {
40-
Some(value as i32)
41-
} else {
42-
None
43-
}
33+
pub fn i64_to_i32(value: i64) {
34+
let _ = i32::try_from(value).is_ok();
35+
let _ = i32::try_from(value).is_ok();
4436
}
4537

46-
fn i64_to_i16(value: i64) -> Option<i16> {
47-
if i16::try_from(value).is_ok() {
48-
Some(value as i16)
49-
} else {
50-
None
51-
}
38+
pub fn i64_to_i16(value: i64) {
39+
let _ = i16::try_from(value).is_ok();
40+
let _ = i16::try_from(value).is_ok();
5241
}
5342

5443
// Unsigned to X
5544

56-
fn u32_to_i32(value: u32) -> Option<i32> {
57-
if i32::try_from(value).is_ok() {
58-
Some(value as i32)
59-
} else {
60-
None
61-
}
45+
pub fn u32_to_i32(value: u32) {
46+
let _ = i32::try_from(value).is_ok();
47+
let _ = i32::try_from(value).is_ok();
6248
}
6349

64-
fn usize_to_isize(value: usize) -> isize {
65-
if isize::try_from(value).is_ok() && value as i32 == 5 {
66-
5
67-
} else {
68-
1
69-
}
50+
pub fn usize_to_isize(value: usize) {
51+
let _ = isize::try_from(value).is_ok() && value as i32 == 5;
52+
let _ = isize::try_from(value).is_ok() && value as i32 == 5;
7053
}
7154

72-
fn u32_to_u16(value: u32) -> isize {
73-
if u16::try_from(value).is_ok() && value as i32 == 5 {
74-
5
75-
} else {
76-
1
77-
}
55+
pub fn u32_to_u16(value: u32) {
56+
let _ = u16::try_from(value).is_ok() && value as i32 == 5;
57+
let _ = u16::try_from(value).is_ok() && value as i32 == 5;
7858
}
7959

8060
// Negative tests
8161

82-
fn no_i64_to_i32(value: i64) -> Option<i32> {
83-
if value <= (i32::max_value() as i64) && value >= 0 {
84-
Some(value as i32)
85-
} else {
86-
None
87-
}
62+
pub fn no_i64_to_i32(value: i64) {
63+
let _ = value <= (i32::max_value() as i64) && value >= 0;
64+
let _ = value <= (i32::MAX as i64) && value >= 0;
8865
}
8966

90-
fn no_isize_to_u8(value: isize) -> Option<u8> {
91-
if value <= (u8::max_value() as isize) && value >= (u8::min_value() as isize) {
92-
Some(value as u8)
93-
} else {
94-
None
95-
}
67+
pub fn no_isize_to_u8(value: isize) {
68+
let _ = value <= (u8::max_value() as isize) && value >= (u8::min_value() as isize);
69+
let _ = value <= (u8::MAX as isize) && value >= (u8::MIN as isize);
9670
}
9771

98-
fn i8_to_u8(value: i8) -> Option<u8> {
99-
if value >= 0 {
100-
Some(value as u8)
101-
} else {
102-
None
103-
}
72+
pub fn i8_to_u8(value: i8) {
73+
let _ = value >= 0;
10474
}
10575

10676
fn main() {}

0 commit comments

Comments
 (0)