aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/semantics.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/semantics.rs')
-rw-r--r--crates/ra_hir/src/semantics.rs154
1 files changed, 83 insertions, 71 deletions
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 9697c7082..758d00409 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -282,83 +282,15 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
282 } 282 }
283 283
284 pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> bool { 284 pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> bool {
285 method_call_expr 285 self.imp.is_unsafe_method_call(method_call_expr)
286 .expr()
287 .and_then(|expr| {
288 let field_expr = if let ast::Expr::FieldExpr(field_expr) = expr {
289 field_expr
290 } else {
291 return None;
292 };
293 let ty = self.type_of_expr(&field_expr.expr()?)?;
294 if !ty.is_packed(self.db) {
295 return None;
296 }
297
298 let func = self.resolve_method_call(&method_call_expr)?;
299 let is_unsafe = func.has_self_param(self.db)
300 && matches!(func.params(self.db).first(), Some(TypeRef::Reference(..)));
301 Some(is_unsafe)
302 })
303 .unwrap_or(false)
304 } 286 }
305 287
306 pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool { 288 pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
307 ref_expr 289 self.imp.is_unsafe_ref_expr(ref_expr)
308 .expr()
309 .and_then(|expr| {
310 let field_expr = match expr {
311 ast::Expr::FieldExpr(field_expr) => field_expr,
312 _ => return None,
313 };
314 let expr = field_expr.expr()?;
315 self.type_of_expr(&expr)
316 })
317 // Binding a reference to a packed type is possibly unsafe.
318 .map(|ty| ty.is_packed(self.db))
319 .unwrap_or(false)
320
321 // FIXME This needs layout computation to be correct. It will highlight
322 // more than it should with the current implementation.
323 } 290 }
324 291
325 pub fn is_unsafe_bind_pat(&self, bind_pat: &ast::BindPat) -> bool { 292 pub fn is_unsafe_bind_pat(&self, bind_pat: &ast::BindPat) -> bool {
326 bind_pat 293 self.imp.is_unsafe_bind_pat(bind_pat)
327 .syntax()
328 .parent()
329 .and_then(|parent| {
330 // `BindPat` can live under `RecordPat` directly under `RecordFieldPat` or
331 // `RecordFieldPatList`. `RecordFieldPat` also lives under `RecordFieldPatList`,
332 // so this tries to lookup the `BindPat` anywhere along that structure to the
333 // `RecordPat` so we can get the containing type.
334 let record_pat = ast::RecordFieldPat::cast(parent.clone())
335 .and_then(|record_pat| record_pat.syntax().parent())
336 .or_else(|| Some(parent.clone()))
337 .and_then(|parent| {
338 ast::RecordFieldPatList::cast(parent)?
339 .syntax()
340 .parent()
341 .and_then(ast::RecordPat::cast)
342 });
343
344 // If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if
345 // this is initialized from a `FieldExpr`.
346 if let Some(record_pat) = record_pat {
347 self.type_of_pat(&ast::Pat::RecordPat(record_pat))
348 } else if let Some(let_stmt) = ast::LetStmt::cast(parent) {
349 let field_expr = match let_stmt.initializer()? {
350 ast::Expr::FieldExpr(field_expr) => field_expr,
351 _ => return None,
352 };
353
354 self.type_of_expr(&field_expr.expr()?)
355 } else {
356 None
357 }
358 })
359 // Binding a reference to a packed type is possibly unsafe.
360 .map(|ty| ty.is_packed(self.db))
361 .unwrap_or(false)
362 } 294 }
363} 295}
364 296
@@ -655,6 +587,86 @@ impl<'db> SemanticsImpl<'db> {
655 }); 587 });
656 InFile::new(file_id, node) 588 InFile::new(file_id, node)
657 } 589 }
590
591 pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> bool {
592 method_call_expr
593 .expr()
594 .and_then(|expr| {
595 let field_expr = if let ast::Expr::FieldExpr(field_expr) = expr {
596 field_expr
597 } else {
598 return None;
599 };
600 let ty = self.type_of_expr(&field_expr.expr()?)?;
601 if !ty.is_packed(self.db) {
602 return None;
603 }
604
605 let func = self.resolve_method_call(&method_call_expr).map(Function::from)?;
606 let is_unsafe = func.has_self_param(self.db)
607 && matches!(func.params(self.db).first(), Some(TypeRef::Reference(..)));
608 Some(is_unsafe)
609 })
610 .unwrap_or(false)
611 }
612
613 pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
614 ref_expr
615 .expr()
616 .and_then(|expr| {
617 let field_expr = match expr {
618 ast::Expr::FieldExpr(field_expr) => field_expr,
619 _ => return None,
620 };
621 let expr = field_expr.expr()?;
622 self.type_of_expr(&expr)
623 })
624 // Binding a reference to a packed type is possibly unsafe.
625 .map(|ty| ty.is_packed(self.db))
626 .unwrap_or(false)
627
628 // FIXME This needs layout computation to be correct. It will highlight
629 // more than it should with the current implementation.
630 }
631
632 pub fn is_unsafe_bind_pat(&self, bind_pat: &ast::BindPat) -> bool {
633 bind_pat
634 .syntax()
635 .parent()
636 .and_then(|parent| {
637 // `BindPat` can live under `RecordPat` directly under `RecordFieldPat` or
638 // `RecordFieldPatList`. `RecordFieldPat` also lives under `RecordFieldPatList`,
639 // so this tries to lookup the `BindPat` anywhere along that structure to the
640 // `RecordPat` so we can get the containing type.
641 let record_pat = ast::RecordFieldPat::cast(parent.clone())
642 .and_then(|record_pat| record_pat.syntax().parent())
643 .or_else(|| Some(parent.clone()))
644 .and_then(|parent| {
645 ast::RecordFieldPatList::cast(parent)?
646 .syntax()
647 .parent()
648 .and_then(ast::RecordPat::cast)
649 });
650
651 // If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if
652 // this is initialized from a `FieldExpr`.
653 if let Some(record_pat) = record_pat {
654 self.type_of_pat(&ast::Pat::RecordPat(record_pat))
655 } else if let Some(let_stmt) = ast::LetStmt::cast(parent) {
656 let field_expr = match let_stmt.initializer()? {
657 ast::Expr::FieldExpr(field_expr) => field_expr,
658 _ => return None,
659 };
660
661 self.type_of_expr(&field_expr.expr()?)
662 } else {
663 None
664 }
665 })
666 // Binding a reference to a packed type is possibly unsafe.
667 .map(|ty| ty.is_packed(self.db))
668 .unwrap_or(false)
669 }
658} 670}
659 671
660pub trait ToDef: AstNode + Clone { 672pub trait ToDef: AstNode + Clone {