aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
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
-rw-r--r--crates/ra_hir/src/source_analyzer.rs7
4 files changed, 120 insertions, 6 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 e3c417b41..36b688ccb 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
@@ -272,6 +273,18 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
272 pub fn assert_contains_node(&self, node: &SyntaxNode) { 273 pub fn assert_contains_node(&self, node: &SyntaxNode) {
273 self.imp.assert_contains_node(node) 274 self.imp.assert_contains_node(node)
274 } 275 }
276
277 pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> bool {
278 self.imp.is_unsafe_method_call(method_call_expr)
279 }
280
281 pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
282 self.imp.is_unsafe_ref_expr(ref_expr)
283 }
284
285 pub fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool {
286 self.imp.is_unsafe_ident_pat(ident_pat)
287 }
275} 288}
276 289
277impl<'db> SemanticsImpl<'db> { 290impl<'db> SemanticsImpl<'db> {
@@ -568,6 +581,90 @@ impl<'db> SemanticsImpl<'db> {
568 }); 581 });
569 InFile::new(file_id, node) 582 InFile::new(file_id, node)
570 } 583 }
584
585 pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> bool {
586 method_call_expr
587 .expr()
588 .and_then(|expr| {
589 let field_expr = if let ast::Expr::FieldExpr(field_expr) = expr {
590 field_expr
591 } else {
592 return None;
593 };
594 let ty = self.type_of_expr(&field_expr.expr()?)?;
595 if !ty.is_packed(self.db) {
596 return None;
597 }
598
599 let func = self.resolve_method_call(&method_call_expr).map(Function::from)?;
600 let is_unsafe = func.has_self_param(self.db)
601 && matches!(func.params(self.db).first(), Some(TypeRef::Reference(..)));
602 Some(is_unsafe)
603 })
604 .unwrap_or(false)
605 }
606
607 pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
608 ref_expr
609 .expr()
610 .and_then(|expr| {
611 let field_expr = match expr {
612 ast::Expr::FieldExpr(field_expr) => field_expr,
613 _ => return None,
614 };
615 let expr = field_expr.expr()?;
616 self.type_of_expr(&expr)
617 })
618 // Binding a reference to a packed type is possibly unsafe.
619 .map(|ty| ty.is_packed(self.db))
620 .unwrap_or(false)
621
622 // FIXME This needs layout computation to be correct. It will highlight
623 // more than it should with the current implementation.
624 }
625
626 pub fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool {
627 if !ident_pat.ref_token().is_some() {
628 return false;
629 }
630
631 ident_pat
632 .syntax()
633 .parent()
634 .and_then(|parent| {
635 // `IdentPat` can live under `RecordPat` directly under `RecordPatField` or
636 // `RecordPatFieldList`. `RecordPatField` also lives under `RecordPatFieldList`,
637 // so this tries to lookup the `IdentPat` anywhere along that structure to the
638 // `RecordPat` so we can get the containing type.
639 let record_pat = ast::RecordPatField::cast(parent.clone())
640 .and_then(|record_pat| record_pat.syntax().parent())
641 .or_else(|| Some(parent.clone()))
642 .and_then(|parent| {
643 ast::RecordPatFieldList::cast(parent)?
644 .syntax()
645 .parent()
646 .and_then(ast::RecordPat::cast)
647 });
648
649 // If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if
650 // this is initialized from a `FieldExpr`.
651 if let Some(record_pat) = record_pat {
652 self.type_of_pat(&ast::Pat::RecordPat(record_pat))
653 } else if let Some(let_stmt) = ast::LetStmt::cast(parent) {
654 let field_expr = match let_stmt.initializer()? {
655 ast::Expr::FieldExpr(field_expr) => field_expr,
656 _ => return None,
657 };
658
659 self.type_of_expr(&field_expr.expr()?)
660 } else {
661 None
662 }
663 })
664 // Binding a reference to a packed type is possibly unsafe.
665 .map(|ty| ty.is_packed(self.db))
666 .unwrap_or(false)
667 }
571} 668}
572 669
573pub trait ToDef: AstNode + Clone { 670pub trait ToDef: AstNode + Clone {
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs
index d0cb62ef0..d3d62debf 100644
--- a/crates/ra_hir/src/source_analyzer.rs
+++ b/crates/ra_hir/src/source_analyzer.rs
@@ -265,8 +265,7 @@ impl SourceAnalyzer {
265 } 265 }
266 266
267 // This must be a normal source file rather than macro file. 267 // This must be a normal source file rather than macro file.
268 let hir_path = 268 let hir_path = Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?;
269 crate::Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?;
270 269
271 // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we 270 // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we
272 // trying to resolve foo::bar. 271 // trying to resolve foo::bar.
@@ -451,7 +450,7 @@ fn adjust(
451pub(crate) fn resolve_hir_path( 450pub(crate) fn resolve_hir_path(
452 db: &dyn HirDatabase, 451 db: &dyn HirDatabase,
453 resolver: &Resolver, 452 resolver: &Resolver,
454 path: &crate::Path, 453 path: &Path,
455) -> Option<PathResolution> { 454) -> Option<PathResolution> {
456 let types = 455 let types =
457 resolver.resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()).map(|ty| match ty { 456 resolver.resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()).map(|ty| match ty {
@@ -512,7 +511,7 @@ pub(crate) fn resolve_hir_path(
512pub(crate) fn resolve_hir_path_qualifier( 511pub(crate) fn resolve_hir_path_qualifier(
513 db: &dyn HirDatabase, 512 db: &dyn HirDatabase,
514 resolver: &Resolver, 513 resolver: &Resolver,
515 path: &crate::Path, 514 path: &Path,
516) -> Option<PathResolution> { 515) -> Option<PathResolution> {
517 let items = resolver 516 let items = resolver
518 .resolve_module_path_in_items(db.upcast(), path.mod_path()) 517 .resolve_module_path_in_items(db.upcast(), path.mod_path())