From 2608a6fd3a024206d4776cc391e46ef28c018434 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Fri, 29 May 2020 08:55:47 -0400 Subject: unsafe: Clean up, improve tracking, add debug_assert Move unsafe_expressions to unsafe_validation.rs, replace vec tracking of child exprs with inline macro, add debug assert to ensure tracked children match walked children exactly --- crates/ra_hir_ty/src/unsafe_validation.rs | 75 ++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) (limited to 'crates/ra_hir_ty/src/unsafe_validation.rs') diff --git a/crates/ra_hir_ty/src/unsafe_validation.rs b/crates/ra_hir_ty/src/unsafe_validation.rs index 55dbe23fa..430182803 100644 --- a/crates/ra_hir_ty/src/unsafe_validation.rs +++ b/crates/ra_hir_ty/src/unsafe_validation.rs @@ -3,13 +3,16 @@ use std::sync::Arc; -use hir_def::FunctionId; +use hir_def::{DefWithBodyId, FunctionId}; use hir_expand::diagnostics::DiagnosticSink; use crate::{ - db::HirDatabase, diagnostics::MissingUnsafe, expr::unsafe_expressions, InferenceResult, + db::HirDatabase, diagnostics::MissingUnsafe, lower::CallableDef, ApplicationTy, + InferenceResult, Ty, TypeCtor, }; +use rustc_hash::FxHashSet; + pub use hir_def::{ body::{ scope::{ExprScopes, ScopeEntry, ScopeId}, @@ -61,3 +64,71 @@ impl<'a, 'b> UnsafeValidator<'a, 'b> { } } } + +pub struct UnsafeExpr { + pub expr: ExprId, + pub inside_unsafe_block: bool, +} + +impl UnsafeExpr { + fn new(expr: ExprId) -> Self { + Self { expr, inside_unsafe_block: false } + } +} + +pub fn unsafe_expressions( + db: &dyn HirDatabase, + infer: &InferenceResult, + def: DefWithBodyId, +) -> Vec { + let mut unsafe_exprs = vec![]; + let mut unsafe_block_exprs = FxHashSet::default(); + let body = db.body(def); + for (id, expr) in body.exprs.iter() { + match expr { + Expr::Unsafe { .. } => { + unsafe_block_exprs.insert(id); + } + Expr::Call { callee, .. } => { + let ty = &infer[*callee]; + if let &Ty::Apply(ApplicationTy { + ctor: TypeCtor::FnDef(CallableDef::FunctionId(func)), + .. + }) = ty + { + if db.function_data(func).is_unsafe { + unsafe_exprs.push(UnsafeExpr::new(id)); + } + } + } + Expr::MethodCall { .. } => { + if infer + .method_resolution(id) + .map(|func| db.function_data(func).is_unsafe) + .unwrap_or(false) + { + unsafe_exprs.push(UnsafeExpr::new(id)); + } + } + Expr::UnaryOp { expr, op: UnaryOp::Deref } => { + if let Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. }) = &infer[*expr] { + unsafe_exprs.push(UnsafeExpr::new(id)); + } + } + _ => {} + } + } + + 'unsafe_exprs: for unsafe_expr in &mut unsafe_exprs { + let mut child = unsafe_expr.expr; + while let Some(parent) = body.parent_map.get(child) { + if unsafe_block_exprs.contains(parent) { + unsafe_expr.inside_unsafe_block = true; + continue 'unsafe_exprs; + } + child = *parent; + } + } + + unsafe_exprs +} -- cgit v1.2.3