aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-08-12 14:20:18 +0100
committerGitHub <[email protected]>2020-08-12 14:20:18 +0100
commit11de7ac2fb6514484076217acb8d93eb36468681 (patch)
treeb727a8db741367634eebf4dc685e0f56fddb2a68 /crates/ra_hir
parent2d41cc0ea323e3c4d97300e4d66de11d6b7148ef (diff)
parent72baf1acdd544c645fd69c16967b91be9e75371b (diff)
Merge #4743
4743: Add tracking of packed repr, use it to highlight unsafe refs r=matklad a=Nashenas88 Taking a reference to a misaligned field on a packed struct is an unsafe operation. Highlight that behavior. Currently, the misaligned part isn't tracked, so this highlight is a bit too aggressive. Fixes #4600 Co-authored-by: Paul Daniel Faria <[email protected]> Co-authored-by: Paul Daniel Faria <[email protected]> Co-authored-by: Paul Daniel Faria <[email protected]>
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/code_model.rs18
-rw-r--r--crates/ra_hir/src/lib.rs2
-rw-r--r--crates/ra_hir/src/semantics.rs99
3 files changed, 117 insertions, 2 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 44456e49e..0007d7fa8 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -4,6 +4,7 @@ use std::{iter, sync::Arc};
4use arrayvec::ArrayVec; 4use arrayvec::ArrayVec;
5use either::Either; 5use either::Either;
6use hir_def::{ 6use hir_def::{
7 adt::ReprKind,
7 adt::StructKind, 8 adt::StructKind,
8 adt::VariantData, 9 adt::VariantData,
9 builtin_type::BuiltinType, 10 builtin_type::BuiltinType,
@@ -431,6 +432,10 @@ impl Struct {
431 Type::from_def(db, self.id.lookup(db.upcast()).container.module(db.upcast()).krate, self.id) 432 Type::from_def(db, self.id.lookup(db.upcast()).container.module(db.upcast()).krate, self.id)
432 } 433 }
433 434
435 pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprKind> {
436 db.struct_data(self.id).repr.clone()
437 }
438
434 fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { 439 fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
435 db.struct_data(self.id).variant_data.clone() 440 db.struct_data(self.id).variant_data.clone()
436 } 441 }
@@ -1253,6 +1258,19 @@ impl Type {
1253 ) 1258 )
1254 } 1259 }
1255 1260
1261 pub fn is_packed(&self, db: &dyn HirDatabase) -> bool {
1262 let adt_id = match self.ty.value {
1263 Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(adt_id), .. }) => adt_id,
1264 _ => return false,
1265 };
1266
1267 let adt = adt_id.into();
1268 match adt {
1269 Adt::Struct(s) => matches!(s.repr(db), Some(ReprKind::Packed)),
1270 _ => false,
1271 }
1272 }
1273
1256 pub fn is_raw_ptr(&self) -> bool { 1274 pub fn is_raw_ptr(&self) -> bool {
1257 matches!(&self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. })) 1275 matches!(&self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. }))
1258 } 1276 }
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 31f3241c9..34b02c536 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -49,7 +49,7 @@ pub use hir_def::{
49 docs::Documentation, 49 docs::Documentation,
50 nameres::ModuleSource, 50 nameres::ModuleSource,
51 path::{ModPath, Path, PathKind}, 51 path::{ModPath, Path, PathKind},
52 type_ref::Mutability, 52 type_ref::{Mutability, TypeRef},
53}; 53};
54pub use hir_expand::{ 54pub use hir_expand::{
55 hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, 55 hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc,
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index e392130ab..872f5fa4c 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -25,7 +25,8 @@ use crate::{
25 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, 25 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
26 source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer}, 26 source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer},
27 AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, 27 AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef,
28 Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef, 28 Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, TypeRef,
29 VariantDef,
29}; 30};
30use resolver::TypeNs; 31use resolver::TypeNs;
31 32
@@ -279,6 +280,18 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
279 pub fn assert_contains_node(&self, node: &SyntaxNode) { 280 pub fn assert_contains_node(&self, node: &SyntaxNode) {
280 self.imp.assert_contains_node(node) 281 self.imp.assert_contains_node(node)
281 } 282 }
283
284 pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> bool {
285 self.imp.is_unsafe_method_call(method_call_expr)
286 }
287
288 pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
289 self.imp.is_unsafe_ref_expr(ref_expr)
290 }
291
292 pub fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool {
293 self.imp.is_unsafe_ident_pat(ident_pat)
294 }
282} 295}
283 296
284impl<'db> SemanticsImpl<'db> { 297impl<'db> SemanticsImpl<'db> {
@@ -574,6 +587,90 @@ impl<'db> SemanticsImpl<'db> {
574 }); 587 });
575 InFile::new(file_id, node) 588 InFile::new(file_id, node)
576 } 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_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool {
633 if !ident_pat.ref_token().is_some() {
634 return false;
635 }
636
637 ident_pat
638 .syntax()
639 .parent()
640 .and_then(|parent| {
641 // `IdentPat` can live under `RecordPat` directly under `RecordPatField` or
642 // `RecordPatFieldList`. `RecordPatField` also lives under `RecordPatFieldList`,
643 // so this tries to lookup the `IdentPat` anywhere along that structure to the
644 // `RecordPat` so we can get the containing type.
645 let record_pat = ast::RecordPatField::cast(parent.clone())
646 .and_then(|record_pat| record_pat.syntax().parent())
647 .or_else(|| Some(parent.clone()))
648 .and_then(|parent| {
649 ast::RecordPatFieldList::cast(parent)?
650 .syntax()
651 .parent()
652 .and_then(ast::RecordPat::cast)
653 });
654
655 // If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if
656 // this is initialized from a `FieldExpr`.
657 if let Some(record_pat) = record_pat {
658 self.type_of_pat(&ast::Pat::RecordPat(record_pat))
659 } else if let Some(let_stmt) = ast::LetStmt::cast(parent) {
660 let field_expr = match let_stmt.initializer()? {
661 ast::Expr::FieldExpr(field_expr) => field_expr,
662 _ => return None,
663 };
664
665 self.type_of_expr(&field_expr.expr()?)
666 } else {
667 None
668 }
669 })
670 // Binding a reference to a packed type is possibly unsafe.
671 .map(|ty| ty.is_packed(self.db))
672 .unwrap_or(false)
673 }
577} 674}
578 675
579pub trait ToDef: AstNode + Clone { 676pub trait ToDef: AstNode + Clone {