aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Daniel Faria <[email protected]>2020-05-24 21:24:36 +0100
committerPaul Daniel Faria <[email protected]>2020-06-27 15:10:26 +0100
commit278cbf12cd0f76fc191d5ce7f130e6245596a578 (patch)
tree7c00307fbef82b45cbd0072a45819ea962bf8900
parent3df0f9ce7e6eea48b67dae8b26e83aa7bd36ff24 (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.rs6
-rw-r--r--crates/ra_hir_def/src/expr.rs5
-rw-r--r--crates/ra_hir_ty/src/expr.rs64
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs1
-rw-r--r--crates/ra_hir_ty/src/tests.rs22
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs1
-rw-r--r--crates/ra_syntax/src/ast/generated/nodes.rs2
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
321pub struct UnsafeExpr {
322 expr: ExprId,
323 inside_unsafe_block: bool,
324}
325
326impl UnsafeExpr {
327 fn new(expr: ExprId) -> Self {
328 Self { expr, inside_unsafe_block: false }
329 }
330}
331
321pub fn unsafe_expressions( 332pub 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
363pub struct UnsafeValidator<'a, 'b: 'a> { 391pub 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
610fn nothing_to_see_move_along() { 610fn 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]
625fn missing_unsafe_diagnostic_with_raw_ptr_outside_unsafe_block() {
626 let diagnostics = TestDB::with_files(
627 r"
628//- /lib.rs
629fn 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 {}
899impl LoopExpr { 899impl 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/// ```