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 | |
parent | 3df0f9ce7e6eea48b67dae8b26e83aa7bd36ff24 (diff) |
Track unsafe blocks, don't trigger missing unsafe diagnostic when unsafe exprs within unsafe block
-rw-r--r-- | crates/ra_hir_def/src/body/lower.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir_def/src/expr.rs | 5 | ||||
-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 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated/nodes.rs | 2 |
7 files changed, 82 insertions, 19 deletions
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index a7e2e0982..174bbf9f4 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -218,8 +218,12 @@ impl ExprCollector<'_> { | |||
218 | let body = self.collect_block_opt(e.block_expr()); | 218 | let body = self.collect_block_opt(e.block_expr()); |
219 | self.alloc_expr(Expr::TryBlock { body }, syntax_ptr) | 219 | self.alloc_expr(Expr::TryBlock { body }, syntax_ptr) |
220 | } | 220 | } |
221 | ast::Effect::Unsafe(_) => { | ||
222 | let body = self.collect_block_opt(e.block_expr()); | ||
223 | self.alloc_expr(Expr::UnsafeBlock { body }, syntax_ptr) | ||
224 | } | ||
221 | // FIXME: we need to record these effects somewhere... | 225 | // FIXME: we need to record these effects somewhere... |
222 | ast::Effect::Async(_) | ast::Effect::Label(_) | ast::Effect::Unsafe(_) => { | 226 | ast::Effect::Async(_) | ast::Effect::Label(_) => { |
223 | self.collect_block_opt(e.block_expr()) | 227 | self.collect_block_opt(e.block_expr()) |
224 | } | 228 | } |
225 | }, | 229 | }, |
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs index ca49b26d1..f5e3e74fb 100644 --- a/crates/ra_hir_def/src/expr.rs +++ b/crates/ra_hir_def/src/expr.rs | |||
@@ -150,6 +150,9 @@ pub enum Expr { | |||
150 | Tuple { | 150 | Tuple { |
151 | exprs: Vec<ExprId>, | 151 | exprs: Vec<ExprId>, |
152 | }, | 152 | }, |
153 | UnsafeBlock { | ||
154 | body: ExprId, | ||
155 | }, | ||
153 | Array(Array), | 156 | Array(Array), |
154 | Literal(Literal), | 157 | Literal(Literal), |
155 | } | 158 | } |
@@ -247,7 +250,7 @@ impl Expr { | |||
247 | f(*expr); | 250 | f(*expr); |
248 | } | 251 | } |
249 | } | 252 | } |
250 | Expr::TryBlock { body } => f(*body), | 253 | Expr::TryBlock { body } | Expr::UnsafeBlock { body } => f(*body), |
251 | Expr::Loop { body, .. } => f(*body), | 254 | Expr::Loop { body, .. } => f(*body), |
252 | Expr::While { condition, body, .. } => { | 255 | Expr::While { condition, body, .. } => { |
253 | f(*condition); | 256 | f(*condition); |
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} |
diff --git a/crates/ra_syntax/src/ast/generated/nodes.rs b/crates/ra_syntax/src/ast/generated/nodes.rs index a2366f997..58141da11 100644 --- a/crates/ra_syntax/src/ast/generated/nodes.rs +++ b/crates/ra_syntax/src/ast/generated/nodes.rs | |||
@@ -899,7 +899,7 @@ impl ast::LoopBodyOwner for LoopExpr {} | |||
899 | impl LoopExpr { | 899 | impl LoopExpr { |
900 | pub fn loop_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![loop]) } | 900 | pub fn loop_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![loop]) } |
901 | } | 901 | } |
902 | /// Block expression with an optional prefix (label, try keyword, | 902 | /// Block expression with an optional prefix (label, try ketword, |
903 | /// unsafe keyword, async keyword...). | 903 | /// unsafe keyword, async keyword...). |
904 | /// | 904 | /// |
905 | /// ``` | 905 | /// ``` |