diff options
Diffstat (limited to 'crates/ra_hir_ty/src/unsafe_validation.rs')
-rw-r--r-- | crates/ra_hir_ty/src/unsafe_validation.rs | 75 |
1 files changed, 73 insertions, 2 deletions
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 @@ | |||
3 | 3 | ||
4 | use std::sync::Arc; | 4 | use std::sync::Arc; |
5 | 5 | ||
6 | use hir_def::FunctionId; | 6 | use hir_def::{DefWithBodyId, FunctionId}; |
7 | use hir_expand::diagnostics::DiagnosticSink; | 7 | use hir_expand::diagnostics::DiagnosticSink; |
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
10 | db::HirDatabase, diagnostics::MissingUnsafe, expr::unsafe_expressions, InferenceResult, | 10 | db::HirDatabase, diagnostics::MissingUnsafe, lower::CallableDef, ApplicationTy, |
11 | InferenceResult, Ty, TypeCtor, | ||
11 | }; | 12 | }; |
12 | 13 | ||
14 | use rustc_hash::FxHashSet; | ||
15 | |||
13 | pub use hir_def::{ | 16 | pub use hir_def::{ |
14 | body::{ | 17 | body::{ |
15 | scope::{ExprScopes, ScopeEntry, ScopeId}, | 18 | scope::{ExprScopes, ScopeEntry, ScopeId}, |
@@ -61,3 +64,71 @@ impl<'a, 'b> UnsafeValidator<'a, 'b> { | |||
61 | } | 64 | } |
62 | } | 65 | } |
63 | } | 66 | } |
67 | |||
68 | pub struct UnsafeExpr { | ||
69 | pub expr: ExprId, | ||
70 | pub inside_unsafe_block: bool, | ||
71 | } | ||
72 | |||
73 | impl UnsafeExpr { | ||
74 | fn new(expr: ExprId) -> Self { | ||
75 | Self { expr, inside_unsafe_block: false } | ||
76 | } | ||
77 | } | ||
78 | |||
79 | pub fn unsafe_expressions( | ||
80 | db: &dyn HirDatabase, | ||
81 | infer: &InferenceResult, | ||
82 | def: DefWithBodyId, | ||
83 | ) -> Vec<UnsafeExpr> { | ||
84 | let mut unsafe_exprs = vec![]; | ||
85 | let mut unsafe_block_exprs = FxHashSet::default(); | ||
86 | let body = db.body(def); | ||
87 | for (id, expr) in body.exprs.iter() { | ||
88 | match expr { | ||
89 | Expr::Unsafe { .. } => { | ||
90 | unsafe_block_exprs.insert(id); | ||
91 | } | ||
92 | Expr::Call { callee, .. } => { | ||
93 | let ty = &infer[*callee]; | ||
94 | if let &Ty::Apply(ApplicationTy { | ||
95 | ctor: TypeCtor::FnDef(CallableDef::FunctionId(func)), | ||
96 | .. | ||
97 | }) = ty | ||
98 | { | ||
99 | if db.function_data(func).is_unsafe { | ||
100 | unsafe_exprs.push(UnsafeExpr::new(id)); | ||
101 | } | ||
102 | } | ||
103 | } | ||
104 | Expr::MethodCall { .. } => { | ||
105 | if infer | ||
106 | .method_resolution(id) | ||
107 | .map(|func| db.function_data(func).is_unsafe) | ||
108 | .unwrap_or(false) | ||
109 | { | ||
110 | unsafe_exprs.push(UnsafeExpr::new(id)); | ||
111 | } | ||
112 | } | ||
113 | Expr::UnaryOp { expr, op: UnaryOp::Deref } => { | ||
114 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. }) = &infer[*expr] { | ||
115 | unsafe_exprs.push(UnsafeExpr::new(id)); | ||
116 | } | ||
117 | } | ||
118 | _ => {} | ||
119 | } | ||
120 | } | ||
121 | |||
122 | 'unsafe_exprs: for unsafe_expr in &mut unsafe_exprs { | ||
123 | let mut child = unsafe_expr.expr; | ||
124 | while let Some(parent) = body.parent_map.get(child) { | ||
125 | if unsafe_block_exprs.contains(parent) { | ||
126 | unsafe_expr.inside_unsafe_block = true; | ||
127 | continue 'unsafe_exprs; | ||
128 | } | ||
129 | child = *parent; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | unsafe_exprs | ||
134 | } | ||