aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r--crates/ra_hir_ty/src/unsafe_validation.rs88
1 files changed, 39 insertions, 49 deletions
diff --git a/crates/ra_hir_ty/src/unsafe_validation.rs b/crates/ra_hir_ty/src/unsafe_validation.rs
index e2353404b..aad13d99c 100644
--- a/crates/ra_hir_ty/src/unsafe_validation.rs
+++ b/crates/ra_hir_ty/src/unsafe_validation.rs
@@ -60,12 +60,6 @@ pub struct UnsafeExpr {
60 pub inside_unsafe_block: bool, 60 pub inside_unsafe_block: bool,
61} 61}
62 62
63impl UnsafeExpr {
64 fn new(expr: ExprId) -> Self {
65 Self { expr, inside_unsafe_block: false }
66 }
67}
68
69pub fn unsafe_expressions( 63pub fn unsafe_expressions(
70 db: &dyn HirDatabase, 64 db: &dyn HirDatabase,
71 infer: &InferenceResult, 65 infer: &InferenceResult,
@@ -73,59 +67,55 @@ pub fn unsafe_expressions(
73) -> Vec<UnsafeExpr> { 67) -> Vec<UnsafeExpr> {
74 let mut unsafe_exprs = vec![]; 68 let mut unsafe_exprs = vec![];
75 let body = db.body(def); 69 let body = db.body(def);
76 for (id, expr) in body.exprs.iter() { 70 walk_unsafe(&mut unsafe_exprs, db, infer, &body, body.body_expr, false);
77 match expr { 71
78 Expr::Call { callee, .. } => { 72 unsafe_exprs
79 let ty = &infer[*callee]; 73}
80 if let &Ty::Apply(ApplicationTy { 74
81 ctor: TypeCtor::FnDef(CallableDef::FunctionId(func)), 75fn walk_unsafe(
82 .. 76 unsafe_exprs: &mut Vec<UnsafeExpr>,
83 }) = ty 77 db: &dyn HirDatabase,
84 { 78 infer: &InferenceResult,
85 if db.function_data(func).is_unsafe { 79 body: &Body,
86 unsafe_exprs.push(UnsafeExpr::new(id)); 80 current: ExprId,
87 } 81 inside_unsafe_block: bool,
82) {
83 let expr = &body.exprs[current];
84 match expr {
85 Expr::Call { callee, .. } => {
86 let ty = &infer[*callee];
87 if let &Ty::Apply(ApplicationTy {
88 ctor: TypeCtor::FnDef(CallableDef::FunctionId(func)),
89 ..
90 }) = ty
91 {
92 if db.function_data(func).is_unsafe {
93 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
88 } 94 }
89 } 95 }
90 Expr::MethodCall { .. } => { 96 }
91 if infer 97 Expr::MethodCall { .. } => {
92 .method_resolution(id) 98 if infer
93 .map(|func| db.function_data(func).is_unsafe) 99 .method_resolution(current)
94 .unwrap_or(false) 100 .map(|func| db.function_data(func).is_unsafe)
95 { 101 .unwrap_or(false)
96 unsafe_exprs.push(UnsafeExpr::new(id)); 102 {
97 } 103 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
98 } 104 }
99 Expr::UnaryOp { expr, op: UnaryOp::Deref } => { 105 }
100 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. }) = &infer[*expr] { 106 Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
101 unsafe_exprs.push(UnsafeExpr::new(id)); 107 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. }) = &infer[*expr] {
102 } 108 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
103 } 109 }
104 _ => {}
105 } 110 }
111 _ => {}
106 } 112 }
107 113
108 for unsafe_expr in &mut unsafe_exprs {
109 unsafe_expr.inside_unsafe_block =
110 is_in_unsafe(&body, body.body_expr, unsafe_expr.expr, false);
111 }
112
113 unsafe_exprs
114}
115
116fn is_in_unsafe(body: &Body, current: ExprId, needle: ExprId, within_unsafe: bool) -> bool {
117 if current == needle {
118 return within_unsafe;
119 }
120
121 let expr = &body.exprs[current];
122 if let &Expr::Unsafe { body: child } = expr { 114 if let &Expr::Unsafe { body: child } = expr {
123 return is_in_unsafe(body, child, needle, true); 115 return walk_unsafe(unsafe_exprs, db, infer, body, child, true);
124 } 116 }
125 117
126 let mut found = false;
127 expr.walk_child_exprs(|child| { 118 expr.walk_child_exprs(|child| {
128 found = found || is_in_unsafe(body, child, needle, within_unsafe); 119 walk_unsafe(unsafe_exprs, db, infer, body, child, inside_unsafe_block);
129 }); 120 });
130 found
131} 121}