Skip to content

Commit 0975031

Browse files
committed
Move cast_sign_loss to its own module
1 parent 0534bf4 commit 0975031

File tree

2 files changed

+78
-66
lines changed

2 files changed

+78
-66
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use rustc_hir::{Expr, ExprKind};
2+
use rustc_lint::LateContext;
3+
use rustc_middle::ty::{self, Ty};
4+
5+
use if_chain::if_chain;
6+
7+
use crate::consts::{constant, Constant};
8+
use crate::utils::{method_chain_args, sext, span_lint};
9+
10+
use super::CAST_SIGN_LOSS;
11+
12+
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
13+
if should_lint(cx, cast_op, cast_from, cast_to) {
14+
span_lint(
15+
cx,
16+
CAST_SIGN_LOSS,
17+
expr.span,
18+
&format!(
19+
"casting `{}` to `{}` may lose the sign of the value",
20+
cast_from, cast_to
21+
),
22+
);
23+
}
24+
}
25+
26+
fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) -> bool {
27+
match (cast_from.is_integral(), cast_to.is_integral()) {
28+
(true, true) => {
29+
if !cast_from.is_signed() || cast_to.is_signed() {
30+
return false;
31+
}
32+
33+
// Don't lint for positive constants.
34+
let const_val = constant(cx, &cx.typeck_results(), cast_op);
35+
if_chain! {
36+
if let Some((Constant::Int(n), _)) = const_val;
37+
if let ty::Int(ity) = *cast_from.kind();
38+
if sext(cx.tcx, n, ity) >= 0;
39+
then {
40+
return false;
41+
}
42+
}
43+
44+
// Don't lint for the result of methods that always return non-negative values.
45+
if let ExprKind::MethodCall(ref path, _, _, _) = cast_op.kind {
46+
let mut method_name = path.ident.name.as_str();
47+
let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"];
48+
49+
if_chain! {
50+
if method_name == "unwrap";
51+
if let Some(arglist) = method_chain_args(cast_op, &["unwrap"]);
52+
if let ExprKind::MethodCall(ref inner_path, _, _, _) = &arglist[0][0].kind;
53+
then {
54+
method_name = inner_path.ident.name.as_str();
55+
}
56+
}
57+
58+
if allowed_methods.iter().any(|&name| method_name == name) {
59+
return false;
60+
}
61+
}
62+
63+
true
64+
},
65+
66+
(false, true) => !cast_to.is_signed(),
67+
68+
(_, _) => false,
69+
}
70+
}

clippy_lints/src/casts/mod.rs

Lines changed: 8 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
mod cast_lossless;
22
mod cast_possible_truncation;
33
mod cast_precision_loss;
4+
mod cast_sign_loss;
45
mod utils;
56

67
use std::borrow::Cow;
@@ -17,11 +18,10 @@ use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
1718
use rustc_span::symbol::sym;
1819
use rustc_target::abi::LayoutOf;
1920

20-
use crate::consts::{constant, Constant};
2121
use crate::utils::sugg::Sugg;
2222
use crate::utils::{
23-
is_hir_ty_cfg_dependant, is_isize_or_usize, meets_msrv, method_chain_args, numeric_literal::NumericLiteral, sext,
24-
snippet_opt, snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then,
23+
is_hir_ty_cfg_dependant, is_isize_or_usize, meets_msrv, numeric_literal::NumericLiteral, snippet_opt,
24+
snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then,
2525
};
2626

2727
use utils::int_ty_to_nbits;
@@ -261,52 +261,6 @@ enum ArchSuffix {
261261
None,
262262
}
263263

264-
fn check_loss_of_sign(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
265-
if !cast_from.is_signed() || cast_to.is_signed() {
266-
return;
267-
}
268-
269-
// don't lint for positive constants
270-
let const_val = constant(cx, &cx.typeck_results(), op);
271-
if_chain! {
272-
if let Some((Constant::Int(n), _)) = const_val;
273-
if let ty::Int(ity) = *cast_from.kind();
274-
if sext(cx.tcx, n, ity) >= 0;
275-
then {
276-
return
277-
}
278-
}
279-
280-
// don't lint for the result of methods that always return non-negative values
281-
if let ExprKind::MethodCall(ref path, _, _, _) = op.kind {
282-
let mut method_name = path.ident.name.as_str();
283-
let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"];
284-
285-
if_chain! {
286-
if method_name == "unwrap";
287-
if let Some(arglist) = method_chain_args(op, &["unwrap"]);
288-
if let ExprKind::MethodCall(ref inner_path, _, _, _) = &arglist[0][0].kind;
289-
then {
290-
method_name = inner_path.ident.name.as_str();
291-
}
292-
}
293-
294-
if allowed_methods.iter().any(|&name| method_name == name) {
295-
return;
296-
}
297-
}
298-
299-
span_lint(
300-
cx,
301-
CAST_SIGN_LOSS,
302-
expr.span,
303-
&format!(
304-
"casting `{}` to `{}` may lose the sign of the value",
305-
cast_from, cast_to
306-
),
307-
);
308-
}
309-
310264
fn check_truncation_and_wrapping(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
311265
let arch_64_suffix = " on targets with 64-bit wide pointers";
312266
let arch_32_suffix = " on targets with 32-bit wide pointers";
@@ -490,29 +444,17 @@ fn show_unnecessary_cast(cx: &LateContext<'_>, expr: &Expr<'_>, literal_str: &st
490444
fn lint_numeric_casts<'tcx>(
491445
cx: &LateContext<'tcx>,
492446
expr: &Expr<'tcx>,
493-
cast_expr: &Expr<'_>,
447+
cast_op: &Expr<'_>,
494448
cast_from: Ty<'tcx>,
495449
cast_to: Ty<'tcx>,
496450
) {
497-
cast_precision_loss::check(cx, expr, cast_from, cast_to);
498-
cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to);
499451
cast_possible_truncation::check(cx, expr, cast_from, cast_to);
452+
cast_precision_loss::check(cx, expr, cast_from, cast_to);
453+
cast_lossless::check(cx, expr, cast_op, cast_from, cast_to);
454+
cast_sign_loss::check(cx, expr, cast_op, cast_from, cast_to);
455+
500456
match (cast_from.is_integral(), cast_to.is_integral()) {
501-
(false, true) => {
502-
if !cast_to.is_signed() {
503-
span_lint(
504-
cx,
505-
CAST_SIGN_LOSS,
506-
expr.span,
507-
&format!(
508-
"casting `{}` to `{}` may lose the sign of the value",
509-
cast_from, cast_to
510-
),
511-
);
512-
}
513-
},
514457
(true, true) => {
515-
check_loss_of_sign(cx, expr, cast_expr, cast_from, cast_to);
516458
check_truncation_and_wrapping(cx, expr, cast_from, cast_to);
517459
},
518460
(_, _) => {},

0 commit comments

Comments
 (0)