diff options
author | Paul Daniel Faria <[email protected]> | 2020-05-24 21:24:36 +0100 |
---|---|---|
committer | Paul Daniel Faria <[email protected]> | 2020-06-27 15:10:26 +0100 |
commit | 278cbf12cd0f76fc191d5ce7f130e6245596a578 (patch) | |
tree | 7c00307fbef82b45cbd0072a45819ea962bf8900 /crates/ra_hir_ty/src | |
parent | 3df0f9ce7e6eea48b67dae8b26e83aa7bd36ff24 (diff) |
Track unsafe blocks, don't trigger missing unsafe diagnostic when unsafe exprs within unsafe block
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r-- | crates/ra_hir_ty/src/expr.rs | 64 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/expr.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests.rs | 22 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/simple.rs | 1 |
4 files changed, 72 insertions, 16 deletions
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs index 1a0710e0b..d600aca21 100644 --- a/crates/ra_hir_ty/src/expr.rs +++ b/crates/ra_hir_ty/src/expr.rs | |||
@@ -318,46 +318,74 @@ pub fn record_pattern_missing_fields( | |||
318 | Some((variant_def, missed_fields, exhaustive)) | 318 | Some((variant_def, missed_fields, exhaustive)) |
319 | } | 319 | } |
320 | 320 | ||
321 | pub struct UnsafeExpr { | ||
322 | expr: ExprId, | ||
323 | inside_unsafe_block: bool, | ||
324 | } | ||
325 | |||
326 | impl UnsafeExpr { | ||
327 | fn new(expr: ExprId) -> Self { | ||
328 | Self { expr, inside_unsafe_block: false } | ||
329 | } | ||
330 | } | ||
331 | |||
321 | pub fn unsafe_expressions( | 332 | pub fn unsafe_expressions( |
322 | db: &dyn HirDatabase, | 333 | db: &dyn HirDatabase, |
323 | infer: &InferenceResult, | 334 | infer: &InferenceResult, |
324 | def: DefWithBodyId, | 335 | def: DefWithBodyId, |
325 | ) -> Vec<ExprId> { | 336 | ) -> Vec<UnsafeExpr> { |
326 | let mut unsafe_expr_ids = vec![]; | 337 | let mut unsafe_exprs = vec![]; |
338 | let mut unsafe_block_scopes = vec![]; | ||
327 | let body = db.body(def); | 339 | let body = db.body(def); |
340 | let expr_scopes = db.expr_scopes(def); | ||
328 | for (id, expr) in body.exprs.iter() { | 341 | for (id, expr) in body.exprs.iter() { |
329 | match expr { | 342 | match expr { |
343 | Expr::UnsafeBlock { body } => { | ||
344 | if let Some(scope) = expr_scopes.scope_for(*body) { | ||
345 | unsafe_block_scopes.push(scope); | ||
346 | } | ||
347 | } | ||
330 | Expr::Call { callee, .. } => { | 348 | Expr::Call { callee, .. } => { |
331 | let ty = &infer.type_of_expr[*callee]; | 349 | let ty = &infer.type_of_expr[*callee]; |
332 | if let &Ty::Apply(ApplicationTy {ctor: TypeCtor::FnDef(CallableDef::FunctionId(func)), .. }) = ty { | 350 | if let &Ty::Apply(ApplicationTy { |
351 | ctor: TypeCtor::FnDef(CallableDef::FunctionId(func)), | ||
352 | .. | ||
353 | }) = ty | ||
354 | { | ||
333 | if db.function_data(func).is_unsafe { | 355 | if db.function_data(func).is_unsafe { |
334 | unsafe_expr_ids.push(id); | 356 | unsafe_exprs.push(UnsafeExpr::new(id)); |
335 | } | 357 | } |
336 | } | 358 | } |
337 | } | 359 | } |
338 | Expr::MethodCall { .. } => { | 360 | Expr::MethodCall { .. } => { |
339 | if infer | 361 | if infer |
340 | .method_resolution(id) | 362 | .method_resolution(id) |
341 | .map(|func| { | 363 | .map(|func| db.function_data(func).is_unsafe) |
342 | db.function_data(func).is_unsafe | 364 | .unwrap_or_else(|| false) |
343 | }) | ||
344 | .unwrap_or_else(|| { | ||
345 | false | ||
346 | }) | ||
347 | { | 365 | { |
348 | unsafe_expr_ids.push(id); | 366 | unsafe_exprs.push(UnsafeExpr::new(id)); |
349 | } | 367 | } |
350 | } | 368 | } |
351 | Expr::UnaryOp { expr, op: UnaryOp::Deref } => { | 369 | Expr::UnaryOp { expr, op: UnaryOp::Deref } => { |
352 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. }) = &infer[*expr] { | 370 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. }) = &infer[*expr] { |
353 | unsafe_expr_ids.push(id); | 371 | unsafe_exprs.push(UnsafeExpr::new(id)); |
354 | } | 372 | } |
355 | } | 373 | } |
356 | _ => {} | 374 | _ => {} |
357 | } | 375 | } |
358 | } | 376 | } |
359 | 377 | ||
360 | unsafe_expr_ids | 378 | 'unsafe_exprs: for unsafe_expr in &mut unsafe_exprs { |
379 | let scope = expr_scopes.scope_for(unsafe_expr.expr); | ||
380 | for scope in expr_scopes.scope_chain(scope) { | ||
381 | if unsafe_block_scopes.contains(&scope) { | ||
382 | unsafe_expr.inside_unsafe_block = true; | ||
383 | continue 'unsafe_exprs; | ||
384 | } | ||
385 | } | ||
386 | } | ||
387 | |||
388 | unsafe_exprs | ||
361 | } | 389 | } |
362 | 390 | ||
363 | pub struct UnsafeValidator<'a, 'b: 'a> { | 391 | pub struct UnsafeValidator<'a, 'b: 'a> { |
@@ -379,7 +407,13 @@ impl<'a, 'b> UnsafeValidator<'a, 'b> { | |||
379 | let def = self.func.into(); | 407 | let def = self.func.into(); |
380 | let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def); | 408 | let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def); |
381 | let func_data = db.function_data(self.func); | 409 | let func_data = db.function_data(self.func); |
382 | if func_data.is_unsafe || unsafe_expressions.len() == 0 { | 410 | if func_data.is_unsafe |
411 | || unsafe_expressions | ||
412 | .into_iter() | ||
413 | .filter(|unsafe_expr| !unsafe_expr.inside_unsafe_block) | ||
414 | .count() | ||
415 | == 0 | ||
416 | { | ||
383 | return; | 417 | return; |
384 | } | 418 | } |
385 | 419 | ||
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index a9565a58d..df7bcb5fa 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs | |||
@@ -142,6 +142,7 @@ impl<'a> InferenceContext<'a> { | |||
142 | // FIXME: Breakable block inference | 142 | // FIXME: Breakable block inference |
143 | self.infer_block(statements, *tail, expected) | 143 | self.infer_block(statements, *tail, expected) |
144 | } | 144 | } |
145 | Expr::UnsafeBlock { body } => self.infer_expr(*body, expected), | ||
145 | Expr::TryBlock { body } => { | 146 | Expr::TryBlock { body } => { |
146 | let _inner = self.infer_expr(*body, expected); | 147 | let _inner = self.infer_expr(*body, expected); |
147 | // FIXME should be std::result::Result<{inner}, _> | 148 | // FIXME should be std::result::Result<{inner}, _> |
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index 8889fa3ba..4bc2e8b27 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs | |||
@@ -608,10 +608,30 @@ fn no_missing_unsafe_diagnostic_with_raw_ptr_in_unsafe_block() { | |||
608 | r" | 608 | r" |
609 | //- /lib.rs | 609 | //- /lib.rs |
610 | fn nothing_to_see_move_along() { | 610 | fn nothing_to_see_move_along() { |
611 | let x = &5 as *const usize; | ||
612 | unsafe { | ||
613 | let y = *x; | ||
614 | } | ||
615 | } | ||
616 | ", | ||
617 | ) | ||
618 | .diagnostics() | ||
619 | .0; | ||
620 | |||
621 | assert_snapshot!(diagnostics, @""); | ||
622 | } | ||
623 | |||
624 | #[test] | ||
625 | fn missing_unsafe_diagnostic_with_raw_ptr_outside_unsafe_block() { | ||
626 | let diagnostics = TestDB::with_files( | ||
627 | r" | ||
628 | //- /lib.rs | ||
629 | fn nothing_to_see_move_along() { | ||
630 | let x = &5 as *const usize; | ||
611 | unsafe { | 631 | unsafe { |
612 | let x = &5 as *const usize; | ||
613 | let y = *x; | 632 | let y = *x; |
614 | } | 633 | } |
634 | let z = *x; | ||
615 | } | 635 | } |
616 | ", | 636 | ", |
617 | ) | 637 | ) |
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index 7d8197f8b..cd919466f 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs | |||
@@ -1880,6 +1880,7 @@ fn main() { | |||
1880 | @r###" | 1880 | @r###" |
1881 | 10..130 '{ ...2 }; }': () | 1881 | 10..130 '{ ...2 }; }': () |
1882 | 20..21 'x': i32 | 1882 | 20..21 'x': i32 |
1883 | 24..37 'unsafe { 92 }': i32 | ||
1883 | 31..37 '{ 92 }': i32 | 1884 | 31..37 '{ 92 }': i32 |
1884 | 33..35 '92': i32 | 1885 | 33..35 '92': i32 |
1885 | 47..48 'y': {unknown} | 1886 | 47..48 'y': {unknown} |