Skip to content

Commit 1849a90

Browse files
committed
fix [unnecessary_cast] ignoring lifetime differences.
With attempt to get expr's hir_ty.
1 parent da4b212 commit 1849a90

File tree

3 files changed

+73
-3
lines changed

3 files changed

+73
-3
lines changed

clippy_lints/src/casts/unnecessary_cast.rs

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::numeric_literal::NumericLiteral;
33
use clippy_utils::source::snippet_opt;
44
use clippy_utils::visitors::{for_each_expr, Visitable};
5-
use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local};
5+
use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local, SpanlessEq};
66
use rustc_ast::{LitFloatType, LitIntType, LitKind};
77
use rustc_errors::Applicability;
88
use rustc_hir::def::{DefKind, Res};
9-
use rustc_hir::{Expr, ExprKind, Lit, Node, Path, QPath, TyKind, UnOp};
9+
use rustc_hir::{self as hir, Expr, ExprKind, Lit, Node, Path, QPath, TyKind, UnOp};
1010
use rustc_lint::{LateContext, LintContext};
1111
use rustc_middle::lint::in_external_macro;
1212
use rustc_middle::ty::{self, FloatTy, InferTy, Ty};
@@ -27,7 +27,7 @@ pub(super) fn check<'tcx>(
2727
if let ty::RawPtr(..) = cast_from.kind()
2828
// check both mutability and type are the same
2929
&& cast_from.kind() == cast_to.kind()
30-
&& let ExprKind::Cast(_, cast_to_hir) = expr.kind
30+
&& let ExprKind::Cast(cast_from_expr, cast_to_hir) = expr.kind
3131
// Ignore casts to e.g. type aliases and infer types
3232
// - p as pointer_alias
3333
// - p as _
@@ -41,6 +41,25 @@ pub(super) fn check<'tcx>(
4141
if is_ty_alias(&qpath) || is_hir_ty_cfg_dependant(cx, to_pointee.ty) {
4242
return false;
4343
}
44+
45+
if let Some(cast_from_hir_ty) = get_expr_hir_ty(cx, cast_from_expr)
46+
&& let TyKind::Ptr(from_pointee) = cast_from_hir_ty.kind
47+
&& let TyKind::Path(QPath::Resolved(
48+
_,
49+
Path {
50+
segments: from_ty_seg, ..
51+
},
52+
)) = from_pointee.ty.kind
53+
&& let QPath::Resolved(
54+
_,
55+
Path {
56+
segments: to_ty_seg, ..
57+
},
58+
) = qpath
59+
&& !SpanlessEq::new(cx).eq_path_segments(from_ty_seg, to_ty_seg)
60+
{
61+
return false;
62+
}
4463
},
4564
// Ignore `p as *const _`
4665
TyKind::Infer => return false,
@@ -300,3 +319,30 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx
300319
fn snippet_eq_ty(snippet: &str, ty: Ty<'_>) -> bool {
301320
snippet.trim() == ty.to_string() || snippet.trim().contains(&format!("::{ty}"))
302321
}
322+
323+
fn get_expr_hir_ty<'hir>(cx: &LateContext<'hir>, expr: &Expr<'hir>) -> Option<&'hir hir::Ty<'hir>> {
324+
match expr.kind {
325+
ExprKind::AddrOf(_, _, inner) => get_expr_hir_ty(cx, inner),
326+
ExprKind::Block(hir::Block { expr: Some(inner), .. }, _) => get_expr_hir_ty(cx, inner),
327+
ExprKind::Cast(_, ty) => Some(ty),
328+
ExprKind::Call(_caller, _) => {
329+
// TODO: handle function call
330+
// println!("calling: {caller:#?}");
331+
None
332+
},
333+
ExprKind::MethodCall(_path, ..) => {
334+
// TODO: handle method call
335+
// println!("calling: {path:#?}");
336+
None
337+
},
338+
ExprKind::Path(_) if let Some(local_id) = path_to_local(expr) => match cx.tcx.parent_hir_node(local_id) {
339+
Node::Param(param) => {
340+
let parent_of_param = cx.tcx.parent_hir_node(param.hir_id);
341+
let fn_decl = parent_of_param.fn_decl()?;
342+
fn_decl.inputs.iter().find(|ty| ty.span == param.ty_span)
343+
},
344+
_ => None,
345+
},
346+
_ => None,
347+
}
348+
}

tests/ui/unnecessary_cast.fixed

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,15 @@ mod fixable {
228228
{ *x }.pow(2)
229229
}
230230
}
231+
232+
fn issue_12860() {
233+
struct Foo<'a>(&'a [u8]);
234+
235+
fn foo<'a, 'b>(x: &'a Foo<'a>) -> &'b Foo<'b> {
236+
unsafe { &*(x as *const Foo<'a> as *const Foo<'b>) }
237+
}
238+
239+
fn bar<'a, 'b>(x: *const Foo<'a>) -> &'b Foo<'b> {
240+
unsafe { &*(x as *const Foo<'b>) }
241+
}
242+
}

tests/ui/unnecessary_cast.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,15 @@ mod fixable {
228228
(*x as usize).pow(2)
229229
}
230230
}
231+
232+
fn issue_12860() {
233+
struct Foo<'a>(&'a [u8]);
234+
235+
fn foo<'a, 'b>(x: &'a Foo<'a>) -> &'b Foo<'b> {
236+
unsafe { &*(x as *const Foo<'a> as *const Foo<'b>) }
237+
}
238+
239+
fn bar<'a, 'b>(x: *const Foo<'a>) -> &'b Foo<'b> {
240+
unsafe { &*(x as *const Foo<'b>) }
241+
}
242+
}

0 commit comments

Comments
 (0)