aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir_def/src/body.rs2
-rw-r--r--crates/ra_hir_def/src/body/lower.rs237
-rw-r--r--crates/ra_hir_ty/src/expr.rs71
-rw-r--r--crates/ra_hir_ty/src/unsafe_validation.rs75
4 files changed, 232 insertions, 153 deletions
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index 076d1a4fa..14a1f4773 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -184,7 +184,7 @@ pub struct Body {
184 /// The `ExprId` of the actual body expression. 184 /// The `ExprId` of the actual body expression.
185 pub body_expr: ExprId, 185 pub body_expr: ExprId,
186 pub item_scope: ItemScope, 186 pub item_scope: ItemScope,
187 pub parent_map: FxHashMap<ExprId, ExprId>, 187 pub parent_map: ArenaMap<ExprId, ExprId>,
188} 188}
189 189
190pub type ExprPtr = AstPtr<ast::Expr>; 190pub type ExprPtr = AstPtr<ast::Expr>;
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index a1678adeb..114b38710 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -7,7 +7,7 @@ use hir_expand::{
7 name::{name, AsName, Name}, 7 name::{name, AsName, Name},
8 HirFileId, MacroDefId, MacroDefKind, 8 HirFileId, MacroDefId, MacroDefKind,
9}; 9};
10use ra_arena::Arena; 10use ra_arena::{map::ArenaMap, Arena};
11use ra_syntax::{ 11use ra_syntax::{
12 ast::{ 12 ast::{
13 self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, ModuleItemOwner, NameOwner, 13 self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, ModuleItemOwner, NameOwner,
@@ -15,7 +15,6 @@ use ra_syntax::{
15 }, 15 },
16 AstNode, AstPtr, 16 AstNode, AstPtr,
17}; 17};
18use rustc_hash::FxHashMap;
19use test_utils::mark; 18use test_utils::mark;
20 19
21use crate::{ 20use crate::{
@@ -75,7 +74,7 @@ pub(super) fn lower(
75 params: Vec::new(), 74 params: Vec::new(),
76 body_expr: dummy_expr_id(), 75 body_expr: dummy_expr_id(),
77 item_scope: Default::default(), 76 item_scope: Default::default(),
78 parent_map: FxHashMap::default(), 77 parent_map: ArenaMap::default(),
79 }, 78 },
80 item_trees: { 79 item_trees: {
81 let mut map = FxHashMap::default(); 80 let mut map = FxHashMap::default();
@@ -97,6 +96,40 @@ struct ExprCollector<'a> {
97 item_trees: FxHashMap<HirFileId, Arc<ItemTree>>, 96 item_trees: FxHashMap<HirFileId, Arc<ItemTree>>,
98} 97}
99 98
99macro_rules! track_parent {
100 (@build $collector:ident, $parent:expr $(,)?) => {
101 $parent
102 };
103 (@build $collector:ident, $parent:expr, opt $expr:ident $($rest:tt)*) => {
104 {
105 if let Some(expr) = $expr {
106 $collector.body.parent_map.insert(expr, $parent);
107 }
108 track_parent!(@build $collector, $parent $($rest)*)
109 }
110 };
111 (@build $collector:ident, $parent:expr, vec $expr:ident $($rest:tt)*) => {
112 {
113 for expr in $expr {
114 $collector.body.parent_map.insert(expr, $parent);
115 }
116 track_parent!(@build $collector, $parent $($rest)*)
117 }
118 };
119 (@build $collector:ident, $parent:expr, $expr:ident $($rest:tt)*) => {
120 {
121 $collector.body.parent_map.insert($expr, $parent);
122 track_parent!(@build $collector, $parent $($rest)*)
123 }
124 };
125 ($collector:ident, $parent:expr, $($rest:tt)*) => {
126 {
127 let parent = $parent;
128 track_parent!(@build $collector, parent, $($rest)*)
129 }
130 }
131}
132
100impl ExprCollector<'_> { 133impl ExprCollector<'_> {
101 fn collect( 134 fn collect(
102 mut self, 135 mut self,
@@ -185,14 +218,42 @@ impl ExprCollector<'_> {
185 } 218 }
186 219
187 fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { 220 fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
188 let parent_and_children = self.collect_expr_inner(expr); 221 let expr_id = self.collect_expr_inner(expr);
189 self.update_parent_map(parent_and_children) 222
223 debug_assert!({
224 let mut found_count = 0;
225 let mut incr = || {
226 found_count += 1;
227 true
228 };
229 let mut all_children_found = true;
230 self.body[expr_id].walk_child_exprs(|child| {
231 all_children_found = all_children_found
232 && self
233 .body
234 .parent_map
235 .get(child)
236 .map(|parent| *parent == expr_id)
237 .unwrap_or(false)
238 && incr()
239 });
240
241 if all_children_found {
242 let child_count_in_map =
243 self.body.parent_map.iter().filter(|&(_, parent)| *parent == expr_id).count();
244 found_count == child_count_in_map
245 } else {
246 false
247 }
248 });
249
250 expr_id
190 } 251 }
191 252
192 fn collect_expr_inner(&mut self, expr: ast::Expr) -> (ExprId, Vec<ExprId>) { 253 fn collect_expr_inner(&mut self, expr: ast::Expr) -> ExprId {
193 let syntax_ptr = AstPtr::new(&expr); 254 let syntax_ptr = AstPtr::new(&expr);
194 if !self.expander.is_cfg_enabled(&expr) { 255 if !self.expander.is_cfg_enabled(&expr) {
195 return (self.missing_expr(), vec![]); 256 return self.missing_expr();
196 } 257 }
197 258
198 match expr { 259 match expr {
@@ -224,48 +285,40 @@ impl ExprCollector<'_> {
224 guard: None, 285 guard: None,
225 }, 286 },
226 ]; 287 ];
227 let children_exprs = if let Some(else_branch) = else_branch { 288 let arm_exprs = arms.iter().map(|arm| arm.expr).collect::<Vec<_>>();
228 vec![match_expr, then_branch, else_branch] 289 return track_parent!(
229 } else { 290 self,
230 vec![match_expr, then_branch]
231 };
232 return (
233 self.alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr), 291 self.alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr),
234 children_exprs, 292 match_expr, vec arm_exprs
235 ); 293 );
236 } 294 }
237 }, 295 },
238 }; 296 };
239 297
240 let children_exprs = if let Some(else_branch) = else_branch { 298 track_parent!(
241 vec![then_branch, else_branch, condition] 299 self,
242 } else {
243 vec![then_branch, condition]
244 };
245
246 (
247 self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr), 300 self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr),
248 children_exprs, 301 then_branch, opt else_branch, condition
249 ) 302 )
250 } 303 }
251 ast::Expr::EffectExpr(e) => match e.effect() { 304 ast::Expr::EffectExpr(e) => match e.effect() {
252 ast::Effect::Try(_) => { 305 ast::Effect::Try(_) => {
253 let body = self.collect_block_opt(e.block_expr()); 306 let body = self.collect_block_opt(e.block_expr());
254 (self.alloc_expr(Expr::TryBlock { body }, syntax_ptr), vec![body]) 307 track_parent!(self, self.alloc_expr(Expr::TryBlock { body }, syntax_ptr), body)
255 } 308 }
256 ast::Effect::Unsafe(_) => { 309 ast::Effect::Unsafe(_) => {
257 let body = self.collect_block_opt(e.block_expr()); 310 let body = self.collect_block_opt(e.block_expr());
258 (self.alloc_expr(Expr::Unsafe { body }, syntax_ptr), vec![body]) 311 track_parent!(self, self.alloc_expr(Expr::Unsafe { body }, syntax_ptr), body)
259 } 312 }
260 // FIXME: we need to record these effects somewhere... 313 // FIXME: we need to record these effects somewhere...
261 ast::Effect::Async(_) | ast::Effect::Label(_) => { 314 ast::Effect::Async(_) | ast::Effect::Label(_) => {
262 (self.collect_block_opt(e.block_expr()), vec![]) 315 self.collect_block_opt(e.block_expr())
263 } 316 }
264 }, 317 },
265 ast::Expr::BlockExpr(e) => (self.collect_block(e), vec![]), 318 ast::Expr::BlockExpr(e) => self.collect_block(e),
266 ast::Expr::LoopExpr(e) => { 319 ast::Expr::LoopExpr(e) => {
267 let body = self.collect_block_opt(e.loop_body()); 320 let body = self.collect_block_opt(e.loop_body());
268 (self.alloc_expr( 321 track_parent!(self, self.alloc_expr(Expr::Loop { body }, syntax_ptr), vec![body])
269 Expr::Loop { 322 Expr::Loop {
270 body, 323 body,
271 label: e 324 label: e
@@ -274,7 +327,7 @@ impl ExprCollector<'_> {
274 .map(|l| Name::new_lifetime(&l)), 327 .map(|l| Name::new_lifetime(&l)),
275 }, 328 },
276 syntax_ptr, 329 syntax_ptr,
277 ), vec![body]) 330 ), body)
278 } 331 }
279 ast::Expr::WhileExpr(e) => { 332 ast::Expr::WhileExpr(e) => {
280 let body = self.collect_block_opt(e.loop_body()); 333 let body = self.collect_block_opt(e.loop_body());
@@ -285,7 +338,6 @@ impl ExprCollector<'_> {
285 None => self.collect_expr_opt(condition.expr()), 338 None => self.collect_expr_opt(condition.expr()),
286 // if let -- desugar to match 339 // if let -- desugar to match
287 Some(pat) => { 340 Some(pat) => {
288 // FIXME(pfaria) track the break and arms parents here?
289 mark::hit!(infer_resolve_while_let); 341 mark::hit!(infer_resolve_while_let);
290 let pat = self.collect_pat(pat); 342 let pat = self.collect_pat(pat);
291 let match_expr = self.collect_expr_opt(condition.expr()); 343 let match_expr = self.collect_expr_opt(condition.expr());
@@ -298,7 +350,7 @@ impl ExprCollector<'_> {
298 ]; 350 ];
299 let match_expr = 351 let match_expr =
300 self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms }); 352 self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms });
301 return (self.alloc_expr( 353 return track_parent!(self, self.alloc_expr(
302 Expr::Loop { 354 Expr::Loop {
303 body: match_expr, 355 body: match_expr,
304 label: e 356 label: e
@@ -307,12 +359,12 @@ impl ExprCollector<'_> {
307 .map(|l| Name::new_lifetime(&l)), 359 .map(|l| Name::new_lifetime(&l)),
308 }, 360 },
309 syntax_ptr, 361 syntax_ptr,
310 ), vec![match_expr]); 362 ), match_expr);
311 } 363 }
312 }, 364 },
313 }; 365 };
314 366
315 (self.alloc_expr( 367 track_parent!(self, self.alloc_expr(
316 Expr::While { 368 Expr::While {
317 condition, 369 condition,
318 body, 370 body,
@@ -322,13 +374,13 @@ impl ExprCollector<'_> {
322 .map(|l| Name::new_lifetime(&l)), 374 .map(|l| Name::new_lifetime(&l)),
323 }, 375 },
324 syntax_ptr, 376 syntax_ptr,
325 ), vec![body, condition]) 377 ), body, condition)
326 } 378 }
327 ast::Expr::ForExpr(e) => { 379 ast::Expr::ForExpr(e) => {
328 let iterable = self.collect_expr_opt(e.iterable()); 380 let iterable = self.collect_expr_opt(e.iterable());
329 let pat = self.collect_pat_opt(e.pat()); 381 let pat = self.collect_pat_opt(e.pat());
330 let body = self.collect_block_opt(e.loop_body()); 382 let body = self.collect_block_opt(e.loop_body());
331 (self.alloc_expr( 383 track_parent!(self, self.alloc_expr(
332 Expr::For { 384 Expr::For {
333 iterable, 385 iterable,
334 pat, 386 pat,
@@ -339,7 +391,7 @@ impl ExprCollector<'_> {
339 .map(|l| Name::new_lifetime(&l)), 391 .map(|l| Name::new_lifetime(&l)),
340 }, 392 },
341 syntax_ptr, 393 syntax_ptr,
342 ), vec![iterable, body]) 394 ), iterable, body)
343 } 395 }
344 ast::Expr::CallExpr(e) => { 396 ast::Expr::CallExpr(e) => {
345 let callee = self.collect_expr_opt(e.expr()); 397 let callee = self.collect_expr_opt(e.expr());
@@ -348,9 +400,7 @@ impl ExprCollector<'_> {
348 } else { 400 } else {
349 Vec::new() 401 Vec::new()
350 }; 402 };
351 let mut children_exprs = args.clone(); 403 track_parent!(self, self.alloc_expr(Expr::Call { callee, args: args.clone() }, syntax_ptr), callee, vec args)
352 children_exprs.push(callee);
353 (self.alloc_expr(Expr::Call { callee, args }, syntax_ptr), children_exprs)
354 } 404 }
355 ast::Expr::MethodCallExpr(e) => { 405 ast::Expr::MethodCallExpr(e) => {
356 let receiver = self.collect_expr_opt(e.expr()); 406 let receiver = self.collect_expr_opt(e.expr());
@@ -362,19 +412,24 @@ impl ExprCollector<'_> {
362 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); 412 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
363 let generic_args = 413 let generic_args =
364 e.type_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx(), it)); 414 e.type_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx(), it));
365 let mut children_exprs = args.clone(); 415 track_parent!(
366 children_exprs.push(receiver); 416 self,
367 (
368 self.alloc_expr( 417 self.alloc_expr(
369 Expr::MethodCall { receiver, method_name, args, generic_args }, 418 Expr::MethodCall {
419 receiver,
420 method_name,
421 args: args.clone(),
422 generic_args
423 },
370 syntax_ptr, 424 syntax_ptr,
371 ), 425 ),
372 children_exprs, 426 receiver,
427 vec args
373 ) 428 )
374 } 429 }
375 ast::Expr::MatchExpr(e) => { 430 ast::Expr::MatchExpr(e) => {
376 let expr = self.collect_expr_opt(e.expr()); 431 let expr = self.collect_expr_opt(e.expr());
377 let (arms, mut children_exprs): (Vec<_>, Vec<_>) = 432 let (arms, children_exprs): (Vec<_>, Vec<_>) =
378 if let Some(match_arm_list) = e.match_arm_list() { 433 if let Some(match_arm_list) = e.match_arm_list() {
379 match_arm_list 434 match_arm_list
380 .arms() 435 .arms()
@@ -396,8 +451,7 @@ impl ExprCollector<'_> {
396 } else { 451 } else {
397 (vec![], vec![]) 452 (vec![], vec![])
398 }; 453 };
399 children_exprs.push(expr); 454 track_parent!(self, self.alloc_expr(Expr::Match { expr, arms: arms.clone() }, syntax_ptr), expr, vec children_exprs)
400 (self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr), children_exprs)
401 } 455 }
402 ast::Expr::PathExpr(e) => { 456 ast::Expr::PathExpr(e) => {
403 let path = e 457 let path = e
@@ -405,7 +459,7 @@ impl ExprCollector<'_> {
405 .and_then(|path| self.expander.parse_path(path)) 459 .and_then(|path| self.expander.parse_path(path))
406 .map(Expr::Path) 460 .map(Expr::Path)
407 .unwrap_or(Expr::Missing); 461 .unwrap_or(Expr::Missing);
408 (self.alloc_expr(path, syntax_ptr), vec![]) 462 self.alloc_expr(path, syntax_ptr)
409 } 463 }
410 ast::Expr::ContinueExpr(e) => (self.alloc_expr( 464 ast::Expr::ContinueExpr(e) => (self.alloc_expr(
411 Expr::Continue { label: e.lifetime_token().map(|l| Name::new_lifetime(&l)) }, 465 Expr::Continue { label: e.lifetime_token().map(|l| Name::new_lifetime(&l)) },
@@ -413,21 +467,21 @@ impl ExprCollector<'_> {
413 ), vec![]), 467 ), vec![]),
414 ast::Expr::BreakExpr(e) => { 468 ast::Expr::BreakExpr(e) => {
415 let expr = e.expr().map(|e| self.collect_expr(e)); 469 let expr = e.expr().map(|e| self.collect_expr(e));
416 (self.alloc_expr( 470 track_parent!(self, self.alloc_expr(
417 Expr::Break { expr, label: e.lifetime_token().map(|l| Name::new_lifetime(&l)) }, 471 Expr::Break { expr, label: e.lifetime_token().map(|l| Name::new_lifetime(&l)) },
418 syntax_ptr, 472 syntax_ptr,
419 ), expr.into_iter().collect()) 473 ), opt expr)
420 } 474 }
421 ast::Expr::ParenExpr(e) => { 475 ast::Expr::ParenExpr(e) => {
422 let inner = self.collect_expr_opt(e.expr()); 476 let inner = self.collect_expr_opt(e.expr());
423 // make the paren expr point to the inner expression as well 477 // make the paren expr point to the inner expression as well
424 let src = self.expander.to_source(syntax_ptr); 478 let src = self.expander.to_source(syntax_ptr);
425 self.source_map.expr_map.insert(src, inner); 479 self.source_map.expr_map.insert(src, inner);
426 (inner, vec![]) 480 inner
427 } 481 }
428 ast::Expr::ReturnExpr(e) => { 482 ast::Expr::ReturnExpr(e) => {
429 let expr = e.expr().map(|e| self.collect_expr(e)); 483 let expr = e.expr().map(|e| self.collect_expr(e));
430 (self.alloc_expr(Expr::Return { expr }, syntax_ptr), expr.into_iter().collect()) 484 track_parent!(self, self.alloc_expr(Expr::Return { expr }, syntax_ptr), opt expr)
431 } 485 }
432 ast::Expr::RecordLit(e) => { 486 ast::Expr::RecordLit(e) => {
433 let path = e.path().and_then(|path| self.expander.parse_path(path)); 487 let path = e.path().and_then(|path| self.expander.parse_path(path));
@@ -463,7 +517,7 @@ impl ExprCollector<'_> {
463 let src = self.expander.to_source(ptr); 517 let src = self.expander.to_source(ptr);
464 self.source_map.field_map.insert((res, i), src); 518 self.source_map.field_map.insert((res, i), src);
465 } 519 }
466 (res, children) 520 track_parent!(self, res, vec children)
467 } 521 }
468 ast::Expr::FieldExpr(e) => { 522 ast::Expr::FieldExpr(e) => {
469 let expr = self.collect_expr_opt(e.expr()); 523 let expr = self.collect_expr_opt(e.expr());
@@ -471,20 +525,24 @@ impl ExprCollector<'_> {
471 Some(kind) => kind.as_name(), 525 Some(kind) => kind.as_name(),
472 _ => Name::missing(), 526 _ => Name::missing(),
473 }; 527 };
474 (self.alloc_expr(Expr::Field { expr, name }, syntax_ptr), vec![expr]) 528 track_parent!(self, self.alloc_expr(Expr::Field { expr, name }, syntax_ptr), expr)
475 } 529 }
476 ast::Expr::AwaitExpr(e) => { 530 ast::Expr::AwaitExpr(e) => {
477 let expr = self.collect_expr_opt(e.expr()); 531 let expr = self.collect_expr_opt(e.expr());
478 (self.alloc_expr(Expr::Await { expr }, syntax_ptr), vec![expr]) 532 track_parent!(self, self.alloc_expr(Expr::Await { expr }, syntax_ptr), expr)
479 } 533 }
480 ast::Expr::TryExpr(e) => { 534 ast::Expr::TryExpr(e) => {
481 let expr = self.collect_expr_opt(e.expr()); 535 let expr = self.collect_expr_opt(e.expr());
482 (self.alloc_expr(Expr::Try { expr }, syntax_ptr), vec![expr]) 536 track_parent!(self, self.alloc_expr(Expr::Try { expr }, syntax_ptr), expr)
483 } 537 }
484 ast::Expr::CastExpr(e) => { 538 ast::Expr::CastExpr(e) => {
485 let expr = self.collect_expr_opt(e.expr()); 539 let expr = self.collect_expr_opt(e.expr());
486 let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.type_ref()); 540 let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.type_ref());
487 (self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr), vec![expr]) 541 track_parent!(
542 self,
543 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr),
544 expr
545 )
488 } 546 }
489 ast::Expr::RefExpr(e) => { 547 ast::Expr::RefExpr(e) => {
490 let expr = self.collect_expr_opt(e.expr()); 548 let expr = self.collect_expr_opt(e.expr());
@@ -501,15 +559,22 @@ impl ExprCollector<'_> {
501 Mutability::from_mutable(e.mut_token().is_some()) 559 Mutability::from_mutable(e.mut_token().is_some())
502 }; 560 };
503 let rawness = Rawness::from_raw(raw_tok); 561 let rawness = Rawness::from_raw(raw_tok);
504 562 track_parent!(
505 self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr) 563 self,
564 self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr),
565 expr
566 )
506 } 567 }
507 ast::Expr::PrefixExpr(e) => { 568 ast::Expr::PrefixExpr(e) => {
508 let expr = self.collect_expr_opt(e.expr()); 569 let expr = self.collect_expr_opt(e.expr());
509 if let Some(op) = e.op_kind() { 570 if let Some(op) = e.op_kind() {
510 (self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr), vec![expr]) 571 track_parent!(
572 self,
573 self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr),
574 expr
575 )
511 } else { 576 } else {
512 (self.alloc_expr(Expr::Missing, syntax_ptr), vec![]) 577 self.alloc_expr(Expr::Missing, syntax_ptr)
513 } 578 }
514 } 579 }
515 ast::Expr::LambdaExpr(e) => { 580 ast::Expr::LambdaExpr(e) => {
@@ -529,24 +594,30 @@ impl ExprCollector<'_> {
529 .and_then(|r| r.type_ref()) 594 .and_then(|r| r.type_ref())
530 .map(|it| TypeRef::from_ast(&self.ctx(), it)); 595 .map(|it| TypeRef::from_ast(&self.ctx(), it));
531 let body = self.collect_expr_opt(e.body()); 596 let body = self.collect_expr_opt(e.body());
532 ( 597 track_parent!(
598 self,
533 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr), 599 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr),
534 vec![body], 600 body,
535 ) 601 )
536 } 602 }
537 ast::Expr::BinExpr(e) => { 603 ast::Expr::BinExpr(e) => {
538 let lhs = self.collect_expr_opt(e.lhs()); 604 let lhs = self.collect_expr_opt(e.lhs());
539 let rhs = self.collect_expr_opt(e.rhs()); 605 let rhs = self.collect_expr_opt(e.rhs());
540 let op = e.op_kind().map(BinaryOp::from); 606 let op = e.op_kind().map(BinaryOp::from);
541 (self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr), vec![lhs, rhs]) 607 track_parent!(
608 self,
609 self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr),
610 lhs,
611 rhs
612 )
542 } 613 }
543 ast::Expr::TupleExpr(e) => { 614 ast::Expr::TupleExpr(e) => {
544 let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect::<Vec<_>>(); 615 let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect::<Vec<_>>();
545 (self.alloc_expr(Expr::Tuple { exprs: exprs.clone() }, syntax_ptr), exprs) 616 track_parent!(self, self.alloc_expr(Expr::Tuple { exprs: exprs.clone() }, syntax_ptr), vec exprs)
546 } 617 }
547 ast::Expr::BoxExpr(e) => { 618 ast::Expr::BoxExpr(e) => {
548 let expr = self.collect_expr_opt(e.expr()); 619 let expr = self.collect_expr_opt(e.expr());
549 (self.alloc_expr(Expr::Box { expr }, syntax_ptr), vec![expr]) 620 track_parent!(self, self.alloc_expr(Expr::Box { expr }, syntax_ptr), expr)
550 } 621 }
551 622
552 ast::Expr::ArrayExpr(e) => { 623 ast::Expr::ArrayExpr(e) => {
@@ -555,45 +626,51 @@ impl ExprCollector<'_> {
555 match kind { 626 match kind {
556 ArrayExprKind::ElementList(e) => { 627 ArrayExprKind::ElementList(e) => {
557 let exprs = e.map(|expr| self.collect_expr(expr)).collect::<Vec<_>>(); 628 let exprs = e.map(|expr| self.collect_expr(expr)).collect::<Vec<_>>();
558 ( 629 track_parent!(self,
559 self.alloc_expr( 630 self.alloc_expr(
560 Expr::Array(Array::ElementList(exprs.clone())), 631 Expr::Array(Array::ElementList(exprs.clone())),
561 syntax_ptr, 632 syntax_ptr,
562 ), 633 ),
563 exprs, 634 vec exprs,
564 ) 635 )
565 } 636 }
566 ArrayExprKind::Repeat { initializer, repeat } => { 637 ArrayExprKind::Repeat { initializer, repeat } => {
567 let initializer = self.collect_expr_opt(initializer); 638 let initializer = self.collect_expr_opt(initializer);
568 let repeat = self.collect_expr_opt(repeat); 639 let repeat = self.collect_expr_opt(repeat);
569 ( 640 track_parent!(
641 self,
570 self.alloc_expr( 642 self.alloc_expr(
571 Expr::Array(Array::Repeat { initializer, repeat }), 643 Expr::Array(Array::Repeat { initializer, repeat }),
572 syntax_ptr, 644 syntax_ptr,
573 ), 645 ),
574 vec![initializer, repeat], 646 initializer,
647 repeat,
575 ) 648 )
576 } 649 }
577 } 650 }
578 } 651 }
579 652
580 ast::Expr::Literal(e) => { 653 ast::Expr::Literal(e) => self.alloc_expr(Expr::Literal(e.kind().into()), syntax_ptr),
581 (self.alloc_expr(Expr::Literal(e.kind().into()), syntax_ptr), vec![])
582 }
583 ast::Expr::IndexExpr(e) => { 654 ast::Expr::IndexExpr(e) => {
584 let base = self.collect_expr_opt(e.base()); 655 let base = self.collect_expr_opt(e.base());
585 let index = self.collect_expr_opt(e.index()); 656 let index = self.collect_expr_opt(e.index());
586 (self.alloc_expr(Expr::Index { base, index }, syntax_ptr), vec![base, index]) 657 track_parent!(
658 self,
659 self.alloc_expr(Expr::Index { base, index }, syntax_ptr),
660 base,
661 index
662 )
587 } 663 }
588 ast::Expr::RangeExpr(e) => { 664 ast::Expr::RangeExpr(e) => {
589 let lhs = e.start().map(|lhs| self.collect_expr(lhs)); 665 let lhs = e.start().map(|lhs| self.collect_expr(lhs));
590 let rhs = e.end().map(|rhs| self.collect_expr(rhs)); 666 let rhs = e.end().map(|rhs| self.collect_expr(rhs));
591 match e.op_kind() { 667 match e.op_kind() {
592 Some(range_type) => ( 668 Some(range_type) => track_parent!(
669 self,
593 self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr), 670 self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr),
594 lhs.into_iter().chain(rhs.into_iter()).collect(), 671 opt lhs, opt rhs
595 ), 672 ),
596 None => (self.alloc_expr(Expr::Missing, syntax_ptr), vec![]), 673 None => self.alloc_expr(Expr::Missing, syntax_ptr),
597 } 674 }
598 } 675 }
599 ast::Expr::MacroCall(e) => { 676 ast::Expr::MacroCall(e) => {
@@ -607,7 +684,7 @@ impl ExprCollector<'_> {
607 self.body.item_scope.define_legacy_macro(name, mac); 684 self.body.item_scope.define_legacy_macro(name, mac);
608 685
609 // FIXME: do we still need to allocate this as missing ? 686 // FIXME: do we still need to allocate this as missing ?
610 (self.alloc_expr(Expr::Missing, syntax_ptr), vec![]) 687 self.alloc_expr(Expr::Missing, syntax_ptr)
611 } else { 688 } else {
612 let macro_call = self.expander.to_source(AstPtr::new(&e)); 689 let macro_call = self.expander.to_source(AstPtr::new(&e));
613 match self.expander.enter_expand(self.db, Some(&self.body.item_scope), e) { 690 match self.expander.enter_expand(self.db, Some(&self.body.item_scope), e) {
@@ -620,15 +697,15 @@ impl ExprCollector<'_> {
620 self.item_trees.insert(self.expander.current_file_id, item_tree); 697 self.item_trees.insert(self.expander.current_file_id, item_tree);
621 let id = self.collect_expr(expansion); 698 let id = self.collect_expr(expansion);
622 self.expander.exit(self.db, mark); 699 self.expander.exit(self.db, mark);
623 (id, vec![]) 700 id
624 } 701 }
625 None => (self.alloc_expr(Expr::Missing, syntax_ptr), vec![]), 702 None => self.alloc_expr(Expr::Missing, syntax_ptr),
626 } 703 }
627 } 704 }
628 } 705 }
629 706
630 // FIXME implement HIR for these: 707 // FIXME implement HIR for these:
631 ast::Expr::Label(_e) => (self.alloc_expr(Expr::Missing, syntax_ptr), vec![]), 708 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
632 } 709 }
633 } 710 }
634 711
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs
index 99eed949f..7db928dde 100644
--- a/crates/ra_hir_ty/src/expr.rs
+++ b/crates/ra_hir_ty/src/expr.rs
@@ -2,7 +2,7 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::{path::path, resolver::HasResolver, AdtId, DefWithBodyId, FunctionId}; 5use hir_def::{path::path, resolver::HasResolver, AdtId, FunctionId};
6use hir_expand::diagnostics::DiagnosticSink; 6use hir_expand::diagnostics::DiagnosticSink;
7use ra_syntax::{ast, AstPtr}; 7use ra_syntax::{ast, AstPtr};
8use rustc_hash::FxHashSet; 8use rustc_hash::FxHashSet;
@@ -10,7 +10,6 @@ use rustc_hash::FxHashSet;
10use crate::{ 10use crate::{
11 db::HirDatabase, 11 db::HirDatabase,
12 diagnostics::{MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields}, 12 diagnostics::{MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields},
13 lower::CallableDef,
14 utils::variant_data, 13 utils::variant_data,
15 ApplicationTy, InferenceResult, Ty, TypeCtor, 14 ApplicationTy, InferenceResult, Ty, TypeCtor,
16 _match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness}, 15 _match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness},
@@ -313,71 +312,3 @@ pub fn record_pattern_missing_fields(
313 } 312 }
314 Some((variant_def, missed_fields, exhaustive)) 313 Some((variant_def, missed_fields, exhaustive))
315} 314}
316
317pub struct UnsafeExpr {
318 pub expr: ExprId,
319 pub inside_unsafe_block: bool,
320}
321
322impl UnsafeExpr {
323 fn new(expr: ExprId) -> Self {
324 Self { expr, inside_unsafe_block: false }
325 }
326}
327
328pub fn unsafe_expressions(
329 db: &dyn HirDatabase,
330 infer: &InferenceResult,
331 def: DefWithBodyId,
332) -> Vec<UnsafeExpr> {
333 let mut unsafe_exprs = vec![];
334 let mut unsafe_block_exprs = FxHashSet::default();
335 let body = db.body(def);
336 for (id, expr) in body.exprs.iter() {
337 match expr {
338 Expr::Unsafe { .. } => {
339 unsafe_block_exprs.insert(id);
340 }
341 Expr::Call { callee, .. } => {
342 let ty = &infer[*callee];
343 if let &Ty::Apply(ApplicationTy {
344 ctor: TypeCtor::FnDef(CallableDef::FunctionId(func)),
345 ..
346 }) = ty
347 {
348 if db.function_data(func).is_unsafe {
349 unsafe_exprs.push(UnsafeExpr::new(id));
350 }
351 }
352 }
353 Expr::MethodCall { .. } => {
354 if infer
355 .method_resolution(id)
356 .map(|func| db.function_data(func).is_unsafe)
357 .unwrap_or(false)
358 {
359 unsafe_exprs.push(UnsafeExpr::new(id));
360 }
361 }
362 Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
363 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. }) = &infer[*expr] {
364 unsafe_exprs.push(UnsafeExpr::new(id));
365 }
366 }
367 _ => {}
368 }
369 }
370
371 'unsafe_exprs: for unsafe_expr in &mut unsafe_exprs {
372 let mut child = unsafe_expr.expr;
373 while let Some(parent) = body.parent_map.get(&child) {
374 if unsafe_block_exprs.contains(parent) {
375 unsafe_expr.inside_unsafe_block = true;
376 continue 'unsafe_exprs;
377 }
378 child = *parent;
379 }
380 }
381
382 unsafe_exprs
383}
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
4use std::sync::Arc; 4use std::sync::Arc;
5 5
6use hir_def::FunctionId; 6use hir_def::{DefWithBodyId, FunctionId};
7use hir_expand::diagnostics::DiagnosticSink; 7use hir_expand::diagnostics::DiagnosticSink;
8 8
9use crate::{ 9use 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
14use rustc_hash::FxHashSet;
15
13pub use hir_def::{ 16pub 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
68pub struct UnsafeExpr {
69 pub expr: ExprId,
70 pub inside_unsafe_block: bool,
71}
72
73impl UnsafeExpr {
74 fn new(expr: ExprId) -> Self {
75 Self { expr, inside_unsafe_block: false }
76 }
77}
78
79pub 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}