use rustc_hir::{Expr, ExprKind}; use rustc_span::sym; use crate::LateContext; /// Given an expression, peel all of casts (` as ...`, `.cast{,_mut,_const}()`, /// `ptr::from_ref()`, ...) and init expressions. /// /// Returns the innermost expression and a boolean representing if one of the casts was /// `UnsafeCell::raw_get()` pub(crate) fn peel_casts<'tcx>( cx: &LateContext<'tcx>, mut e: &'tcx Expr<'tcx>, ) -> (&'tcx Expr<'tcx>, bool) { let mut gone_trough_unsafe_cell_raw_get = false; loop { e = e.peel_blocks(); // as ... e = if let ExprKind::Cast(expr, _) = e.kind { expr // .cast(), .cast_mut() or .cast_const() } else if let ExprKind::MethodCall(_, expr, [], _) = e.kind && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) && matches!( cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_cast | sym::const_ptr_cast | sym::ptr_cast_mut | sym::ptr_cast_const) ) { expr // ptr::from_ref(), UnsafeCell::raw_get() or mem::transmute<_, _>() } else if let ExprKind::Call(path, [arg]) = e.kind && let ExprKind::Path(ref qpath) = path.kind && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() && matches!( cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_from_ref | sym::unsafe_cell_raw_get | sym::transmute) ) { if cx.tcx.is_diagnostic_item(sym::unsafe_cell_raw_get, def_id) { gone_trough_unsafe_cell_raw_get = true; } arg } else { let init = cx.expr_or_init(e); if init.hir_id != e.hir_id { init } else { break; } }; } (e, gone_trough_unsafe_cell_raw_get) }