[cast_lossless]: Suggest type alias instead of the aliased type
This commit is contained in:
parent
3a149111ba
commit
244d7da817
11 changed files with 127 additions and 59 deletions
|
|
@ -1,10 +1,10 @@
|
|||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::in_constant;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
|
||||
use clippy_utils::ty::is_isize_or_usize;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_hir::{Expr, ExprKind, QPath, TyKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, FloatTy, Ty};
|
||||
|
||||
|
|
@ -16,6 +16,7 @@ pub(super) fn check(
|
|||
cast_op: &Expr<'_>,
|
||||
cast_from: Ty<'_>,
|
||||
cast_to: Ty<'_>,
|
||||
cast_to_hir: &rustc_hir::Ty<'_>,
|
||||
msrv: &Msrv,
|
||||
) {
|
||||
if !should_lint(cx, expr, cast_from, cast_to, msrv) {
|
||||
|
|
@ -24,11 +25,11 @@ pub(super) fn check(
|
|||
|
||||
// The suggestion is to use a function call, so if the original expression
|
||||
// has parens on the outside, they are no longer needed.
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let opt = snippet_opt(cx, cast_op.span.source_callsite());
|
||||
let sugg = opt.as_ref().map_or_else(
|
||||
|| {
|
||||
applicability = Applicability::HasPlaceholders;
|
||||
app = Applicability::HasPlaceholders;
|
||||
".."
|
||||
},
|
||||
|snip| {
|
||||
|
|
@ -40,10 +41,27 @@ pub(super) fn check(
|
|||
},
|
||||
);
|
||||
|
||||
let message = if cast_from.is_bool() {
|
||||
format!("casting `{cast_from:}` to `{cast_to:}` is more cleanly stated with `{cast_to:}::from(_)`")
|
||||
// Display the type alias instead of the aliased type. Fixes #11285
|
||||
//
|
||||
// FIXME: Once `lazy_type_alias` is stabilized(?) we should use `rustc_middle` types instead,
|
||||
// this will allow us to display the right type with `cast_from` as well.
|
||||
let cast_to_fmt = if let TyKind::Path(QPath::Resolved(None, path)) = cast_to_hir.kind
|
||||
// It's a bit annoying but the turbofish is optional for types. A type in an `as` cast
|
||||
// shouldn't have these if they're primitives, which are the only things we deal with.
|
||||
//
|
||||
// This could be removed for performance if this check is determined to have a pretty major
|
||||
// effect.
|
||||
&& path.segments.iter().all(|segment| segment.args.is_none())
|
||||
{
|
||||
snippet_with_applicability(cx, cast_to_hir.span, "..", &mut app)
|
||||
} else {
|
||||
format!("casting `{cast_from}` to `{cast_to}` may become silently lossy if you later change the type")
|
||||
cast_to.to_string().into()
|
||||
};
|
||||
|
||||
let message = if cast_from.is_bool() {
|
||||
format!("casting `{cast_from}` to `{cast_to_fmt}` is more cleanly stated with `{cast_to_fmt}::from(_)`")
|
||||
} else {
|
||||
format!("casting `{cast_from}` to `{cast_to_fmt}` may become silently lossy if you later change the type")
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
|
|
@ -52,8 +70,8 @@ pub(super) fn check(
|
|||
expr.span,
|
||||
&message,
|
||||
"try",
|
||||
format!("{cast_to}::from({sugg})"),
|
||||
applicability,
|
||||
format!("{cast_to_fmt}::from({sugg})"),
|
||||
app,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -791,7 +791,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
|
|||
cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
|
||||
cast_nan_to_int::check(cx, expr, cast_expr, cast_from, cast_to);
|
||||
}
|
||||
cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
|
||||
cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir, &self.msrv);
|
||||
cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue