| use rustc_hir as hir; |
| use rustc_hir_pretty::qpath_to_string; |
| use rustc_lint_defs::builtin::STATIC_MUT_REFS; |
| use rustc_middle::ty::{Mutability, TyCtxt}; |
| use rustc_span::Span; |
| |
| use crate::errors; |
| |
| /// Check for shared or mutable references of `static mut` inside expression |
| pub fn maybe_expr_static_mut(tcx: TyCtxt<'_>, expr: hir::Expr<'_>) { |
| let span = expr.span; |
| let hir_id = expr.hir_id; |
| if let hir::ExprKind::AddrOf(borrow_kind, m, expr) = expr.kind |
| && matches!(borrow_kind, hir::BorrowKind::Ref) |
| && let Some(var) = path_if_static_mut(tcx, expr) |
| { |
| handle_static_mut_ref(tcx, span, var, span.edition().at_least_rust_2024(), m, hir_id); |
| } |
| } |
| |
| /// Check for shared or mutable references of `static mut` inside statement |
| pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) { |
| if let hir::StmtKind::Let(loc) = stmt.kind |
| && let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind |
| && let hir::ByRef::Yes(rmutbl) = ba.0 |
| && let Some(init) = loc.init |
| && let Some(var) = path_if_static_mut(tcx, init) |
| { |
| handle_static_mut_ref( |
| tcx, |
| init.span, |
| var, |
| loc.span.edition().at_least_rust_2024(), |
| rmutbl, |
| stmt.hir_id, |
| ); |
| } |
| } |
| |
| fn path_if_static_mut(tcx: TyCtxt<'_>, expr: &hir::Expr<'_>) -> Option<String> { |
| if let hir::ExprKind::Path(qpath) = expr.kind |
| && let hir::QPath::Resolved(_, path) = qpath |
| && let hir::def::Res::Def(def_kind, _) = path.res |
| && let hir::def::DefKind::Static { mutability: Mutability::Mut, nested: false } = def_kind |
| { |
| return Some(qpath_to_string(&tcx, &qpath)); |
| } |
| None |
| } |
| |
| fn handle_static_mut_ref( |
| tcx: TyCtxt<'_>, |
| span: Span, |
| var: String, |
| e2024: bool, |
| mutable: Mutability, |
| hir_id: hir::HirId, |
| ) { |
| if e2024 { |
| let (sugg, shared) = if mutable == Mutability::Mut { |
| (errors::StaticMutRefSugg::Mut { span, var }, "mutable") |
| } else { |
| (errors::StaticMutRefSugg::Shared { span, var }, "shared") |
| }; |
| tcx.sess.psess.dcx.emit_err(errors::StaticMutRef { span, sugg, shared }); |
| } else { |
| let (sugg, shared) = if mutable == Mutability::Mut { |
| (errors::RefOfMutStaticSugg::Mut { span, var }, "mutable") |
| } else { |
| (errors::RefOfMutStaticSugg::Shared { span, var }, "shared") |
| }; |
| tcx.emit_node_span_lint( |
| STATIC_MUT_REFS, |
| hir_id, |
| span, |
| errors::RefOfMutStatic { span, sugg, shared }, |
| ); |
| } |
| } |