1 use clippy_utils
::consts
::{constant, Constant}
;
2 use clippy_utils
::diagnostics
::span_lint
;
3 use clippy_utils
::{method_chain_args, sext}
;
4 use if_chain
::if_chain
;
5 use rustc_hir
::{Expr, ExprKind}
;
6 use rustc_lint
::LateContext
;
7 use rustc_middle
::ty
::{self, Ty}
;
9 use super::CAST_SIGN_LOSS
;
11 pub(super) fn check(cx
: &LateContext
<'_
>, expr
: &Expr
<'_
>, cast_op
: &Expr
<'_
>, cast_from
: Ty
<'_
>, cast_to
: Ty
<'_
>) {
12 if should_lint(cx
, cast_op
, cast_from
, cast_to
) {
18 "casting `{}` to `{}` may lose the sign of the value",
25 fn should_lint(cx
: &LateContext
<'_
>, cast_op
: &Expr
<'_
>, cast_from
: Ty
<'_
>, cast_to
: Ty
<'_
>) -> bool
{
26 match (cast_from
.is_integral(), cast_to
.is_integral()) {
28 if !cast_from
.is_signed() || cast_to
.is_signed() {
32 // Don't lint for positive constants.
33 let const_val
= constant(cx
, cx
.typeck_results(), cast_op
);
35 if let Some((Constant
::Int(n
), _
)) = const_val
;
36 if let ty
::Int(ity
) = *cast_from
.kind();
37 if sext(cx
.tcx
, n
, ity
) >= 0;
43 // Don't lint for the result of methods that always return non-negative values.
44 if let ExprKind
::MethodCall(path
, _
, _
, _
) = cast_op
.kind
{
45 let mut method_name
= path
.ident
.name
.as_str();
46 let allowed_methods
= ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"];
49 if method_name
== "unwrap";
50 if let Some(arglist
) = method_chain_args(cast_op
, &["unwrap"]);
51 if let ExprKind
::MethodCall(inner_path
, _
, _
, _
) = &arglist
[0][0].kind
;
53 method_name
= inner_path
.ident
.name
.as_str();
57 if allowed_methods
.iter().any(|&name
| method_name
== name
) {
65 (false, true) => !cast_to
.is_signed(),