Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 9709993

Browse files
committed
Move unnecessary_cast to its own module
1 parent a383e03 commit 9709993

File tree

2 files changed

+128
-98
lines changed

2 files changed

+128
-98
lines changed

clippy_lints/src/casts/mod.rs

Lines changed: 22 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,26 @@ mod cast_possible_truncation;
33
mod cast_possible_wrap;
44
mod cast_precision_loss;
55
mod cast_sign_loss;
6+
mod unnecessary_cast;
67
mod utils;
78

89
use std::borrow::Cow;
910

1011
use if_chain::if_chain;
11-
use rustc_ast::{LitFloatType, LitIntType, LitKind};
12+
use rustc_ast::LitKind;
1213
use rustc_errors::Applicability;
13-
use rustc_hir::{Expr, ExprKind, GenericArg, Lit, MutTy, Mutability, TyKind, UnOp};
14+
use rustc_hir::{Expr, ExprKind, GenericArg, MutTy, Mutability, TyKind, UnOp};
1415
use rustc_lint::{LateContext, LateLintPass, LintContext};
1516
use rustc_middle::lint::in_external_macro;
16-
use rustc_middle::ty::{self, FloatTy, InferTy, Ty, TypeAndMut, UintTy};
17+
use rustc_middle::ty::{self, Ty, TypeAndMut, UintTy};
1718
use rustc_semver::RustcVersion;
1819
use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
1920
use rustc_span::symbol::sym;
2021
use rustc_target::abi::LayoutOf;
2122

2223
use crate::utils::sugg::Sugg;
2324
use crate::utils::{
24-
is_hir_ty_cfg_dependant, meets_msrv, numeric_literal::NumericLiteral, snippet_opt, snippet_with_applicability,
25-
span_lint, span_lint_and_sugg, span_lint_and_then,
25+
is_hir_ty_cfg_dependant, meets_msrv, snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then,
2626
};
2727

2828
use utils::int_ty_to_nbits;
@@ -284,72 +284,25 @@ fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
284284
false
285285
}
286286

287-
/// Returns the mantissa bits wide of a fp type.
288-
/// Will return 0 if the type is not a fp
289-
fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 {
290-
match typ.kind() {
291-
ty::Float(FloatTy::F32) => 23,
292-
ty::Float(FloatTy::F64) | ty::Infer(InferTy::FloatVar(_)) => 52,
293-
_ => 0,
294-
}
295-
}
296-
297287
impl<'tcx> LateLintPass<'tcx> for Casts {
298288
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
299289
if expr.span.from_expansion() {
300290
return;
301291
}
302-
if let ExprKind::Cast(ref ex, cast_to) = expr.kind {
292+
if let ExprKind::Cast(ref cast_expr, cast_to) = expr.kind {
303293
if is_hir_ty_cfg_dependant(cx, cast_to) {
304294
return;
305295
}
306-
let (cast_from, cast_to) = (cx.typeck_results().expr_ty(ex), cx.typeck_results().expr_ty(expr));
307-
lint_fn_to_numeric_cast(cx, expr, ex, cast_from, cast_to);
308-
if let Some(lit) = get_numeric_literal(ex) {
309-
let literal_str = snippet_opt(cx, ex.span).unwrap_or_default();
310-
311-
if_chain! {
312-
if let LitKind::Int(n, _) = lit.node;
313-
if let Some(src) = snippet_opt(cx, lit.span);
314-
if cast_to.is_floating_point();
315-
if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node);
316-
let from_nbits = 128 - n.leading_zeros();
317-
let to_nbits = fp_ty_mantissa_nbits(cast_to);
318-
if from_nbits != 0 && to_nbits != 0 && from_nbits <= to_nbits && num_lit.is_decimal();
319-
then {
320-
let literal_str = if is_unary_neg(ex) { format!("-{}", num_lit.integer) } else { num_lit.integer.into() };
321-
show_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
322-
return;
323-
}
324-
}
325-
326-
match lit.node {
327-
LitKind::Int(_, LitIntType::Unsuffixed) if cast_to.is_integral() => {
328-
show_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
329-
},
330-
LitKind::Float(_, LitFloatType::Unsuffixed) if cast_to.is_floating_point() => {
331-
show_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
332-
},
333-
LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) => {},
334-
_ => {
335-
if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) {
336-
span_lint(
337-
cx,
338-
UNNECESSARY_CAST,
339-
expr.span,
340-
&format!(
341-
"casting to the same type is unnecessary (`{}` -> `{}`)",
342-
cast_from, cast_to
343-
),
344-
);
345-
}
346-
},
347-
}
348-
}
349-
if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
350-
lint_numeric_casts(cx, expr, ex, cast_from, cast_to);
351-
}
296+
let (cast_from, cast_to) = (
297+
cx.typeck_results().expr_ty(cast_expr),
298+
cx.typeck_results().expr_ty(expr),
299+
);
352300

301+
if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) {
302+
return;
303+
}
304+
lint_fn_to_numeric_cast(cx, expr, cast_expr, cast_from, cast_to);
305+
lint_numeric_casts(cx, expr, cast_expr, cast_from, cast_to);
353306
lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
354307
} else if let ExprKind::MethodCall(method_path, _, args, _) = expr.kind {
355308
if_chain! {
@@ -368,49 +321,20 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
368321
}
369322
}
370323

371-
fn is_unary_neg(expr: &Expr<'_>) -> bool {
372-
matches!(expr.kind, ExprKind::Unary(UnOp::Neg, _))
373-
}
374-
375-
fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<&'e Lit> {
376-
match expr.kind {
377-
ExprKind::Lit(ref lit) => Some(lit),
378-
ExprKind::Unary(UnOp::Neg, e) => {
379-
if let ExprKind::Lit(ref lit) = e.kind {
380-
Some(lit)
381-
} else {
382-
None
383-
}
384-
},
385-
_ => None,
386-
}
387-
}
388-
389-
fn show_unnecessary_cast(cx: &LateContext<'_>, expr: &Expr<'_>, literal_str: &str, cast_from: Ty<'_>, cast_to: Ty<'_>) {
390-
let literal_kind_name = if cast_from.is_integral() { "integer" } else { "float" };
391-
span_lint_and_sugg(
392-
cx,
393-
UNNECESSARY_CAST,
394-
expr.span,
395-
&format!("casting {} literal to `{}` is unnecessary", literal_kind_name, cast_to),
396-
"try",
397-
format!("{}_{}", literal_str.trim_end_matches('.'), cast_to),
398-
Applicability::MachineApplicable,
399-
);
400-
}
401-
402324
fn lint_numeric_casts<'tcx>(
403325
cx: &LateContext<'tcx>,
404326
expr: &Expr<'tcx>,
405327
cast_op: &Expr<'_>,
406328
cast_from: Ty<'tcx>,
407329
cast_to: Ty<'tcx>,
408330
) {
409-
cast_possible_truncation::check(cx, expr, cast_from, cast_to);
410-
cast_possible_wrap::check(cx, expr, cast_from, cast_to);
411-
cast_precision_loss::check(cx, expr, cast_from, cast_to);
412-
cast_lossless::check(cx, expr, cast_op, cast_from, cast_to);
413-
cast_sign_loss::check(cx, expr, cast_op, cast_from, cast_to);
331+
if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
332+
cast_possible_truncation::check(cx, expr, cast_from, cast_to);
333+
cast_possible_wrap::check(cx, expr, cast_from, cast_to);
334+
cast_precision_loss::check(cx, expr, cast_from, cast_to);
335+
cast_lossless::check(cx, expr, cast_op, cast_from, cast_to);
336+
cast_sign_loss::check(cx, expr, cast_op, cast_from, cast_to);
337+
}
414338
}
415339

416340
fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_from: Ty<'tcx>, cast_to: Ty<'tcx>) {
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
use rustc_ast::{LitFloatType, LitIntType, LitKind};
2+
use rustc_errors::Applicability;
3+
use rustc_hir::{Expr, ExprKind, Lit, UnOp};
4+
use rustc_lint::{LateContext, LintContext};
5+
use rustc_middle::lint::in_external_macro;
6+
use rustc_middle::ty::{self, FloatTy, InferTy, Ty};
7+
8+
use if_chain::if_chain;
9+
10+
use crate::utils::{numeric_literal::NumericLiteral, snippet_opt, span_lint, span_lint_and_sugg};
11+
12+
use super::UNNECESSARY_CAST;
13+
14+
pub(super) fn check(
15+
cx: &LateContext<'_>,
16+
expr: &Expr<'_>,
17+
cast_expr: &Expr<'_>,
18+
cast_from: Ty<'_>,
19+
cast_to: Ty<'_>,
20+
) -> bool {
21+
if let Some(lit) = get_numeric_literal(cast_expr) {
22+
let literal_str = snippet_opt(cx, cast_expr.span).unwrap_or_default();
23+
24+
if_chain! {
25+
if let LitKind::Int(n, _) = lit.node;
26+
if let Some(src) = snippet_opt(cx, lit.span);
27+
if cast_to.is_floating_point();
28+
if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node);
29+
let from_nbits = 128 - n.leading_zeros();
30+
let to_nbits = fp_ty_mantissa_nbits(cast_to);
31+
if from_nbits != 0 && to_nbits != 0 && from_nbits <= to_nbits && num_lit.is_decimal();
32+
then {
33+
let literal_str = if is_unary_neg(cast_expr) { format!("-{}", num_lit.integer) } else { num_lit.integer.into() };
34+
lint_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
35+
return true
36+
}
37+
}
38+
39+
match lit.node {
40+
LitKind::Int(_, LitIntType::Unsuffixed) if cast_to.is_integral() => {
41+
lint_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
42+
},
43+
LitKind::Float(_, LitFloatType::Unsuffixed) if cast_to.is_floating_point() => {
44+
lint_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
45+
},
46+
LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) => {},
47+
_ => {
48+
if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) {
49+
span_lint(
50+
cx,
51+
UNNECESSARY_CAST,
52+
expr.span,
53+
&format!(
54+
"casting to the same type is unnecessary (`{}` -> `{}`)",
55+
cast_from, cast_to
56+
),
57+
);
58+
return true;
59+
}
60+
},
61+
}
62+
}
63+
64+
false
65+
}
66+
67+
fn lint_unnecessary_cast(cx: &LateContext<'_>, expr: &Expr<'_>, literal_str: &str, cast_from: Ty<'_>, cast_to: Ty<'_>) {
68+
let literal_kind_name = if cast_from.is_integral() { "integer" } else { "float" };
69+
span_lint_and_sugg(
70+
cx,
71+
UNNECESSARY_CAST,
72+
expr.span,
73+
&format!("casting {} literal to `{}` is unnecessary", literal_kind_name, cast_to),
74+
"try",
75+
format!("{}_{}", literal_str.trim_end_matches('.'), cast_to),
76+
Applicability::MachineApplicable,
77+
);
78+
}
79+
80+
fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<&'e Lit> {
81+
match expr.kind {
82+
ExprKind::Lit(ref lit) => Some(lit),
83+
ExprKind::Unary(UnOp::Neg, e) => {
84+
if let ExprKind::Lit(ref lit) = e.kind {
85+
Some(lit)
86+
} else {
87+
None
88+
}
89+
},
90+
_ => None,
91+
}
92+
}
93+
94+
/// Returns the mantissa bits wide of a fp type.
95+
/// Will return 0 if the type is not a fp
96+
fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 {
97+
match typ.kind() {
98+
ty::Float(FloatTy::F32) => 23,
99+
ty::Float(FloatTy::F64) | ty::Infer(InferTy::FloatVar(_)) => 52,
100+
_ => 0,
101+
}
102+
}
103+
104+
fn is_unary_neg(expr: &Expr<'_>) -> bool {
105+
matches!(expr.kind, ExprKind::Unary(UnOp::Neg, _))
106+
}

0 commit comments

Comments
 (0)