Move unsafe semantics methods into SemanticsImpl and reference them in Semantics

This commit is contained in:
Paul Daniel Faria 2020-07-30 09:26:40 -04:00
parent 39fdd41df4
commit 61dff939f9

View file

@ -282,83 +282,15 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
}
pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> bool {
method_call_expr
.expr()
.and_then(|expr| {
let field_expr = if let ast::Expr::FieldExpr(field_expr) = expr {
field_expr
} else {
return None;
};
let ty = self.type_of_expr(&field_expr.expr()?)?;
if !ty.is_packed(self.db) {
return None;
}
let func = self.resolve_method_call(&method_call_expr)?;
let is_unsafe = func.has_self_param(self.db)
&& matches!(func.params(self.db).first(), Some(TypeRef::Reference(..)));
Some(is_unsafe)
})
.unwrap_or(false)
self.imp.is_unsafe_method_call(method_call_expr)
}
pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
ref_expr
.expr()
.and_then(|expr| {
let field_expr = match expr {
ast::Expr::FieldExpr(field_expr) => field_expr,
_ => return None,
};
let expr = field_expr.expr()?;
self.type_of_expr(&expr)
})
// Binding a reference to a packed type is possibly unsafe.
.map(|ty| ty.is_packed(self.db))
.unwrap_or(false)
// FIXME This needs layout computation to be correct. It will highlight
// more than it should with the current implementation.
self.imp.is_unsafe_ref_expr(ref_expr)
}
pub fn is_unsafe_bind_pat(&self, bind_pat: &ast::BindPat) -> bool {
bind_pat
.syntax()
.parent()
.and_then(|parent| {
// `BindPat` can live under `RecordPat` directly under `RecordFieldPat` or
// `RecordFieldPatList`. `RecordFieldPat` also lives under `RecordFieldPatList`,
// so this tries to lookup the `BindPat` anywhere along that structure to the
// `RecordPat` so we can get the containing type.
let record_pat = ast::RecordFieldPat::cast(parent.clone())
.and_then(|record_pat| record_pat.syntax().parent())
.or_else(|| Some(parent.clone()))
.and_then(|parent| {
ast::RecordFieldPatList::cast(parent)?
.syntax()
.parent()
.and_then(ast::RecordPat::cast)
});
// If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if
// this is initialized from a `FieldExpr`.
if let Some(record_pat) = record_pat {
self.type_of_pat(&ast::Pat::RecordPat(record_pat))
} else if let Some(let_stmt) = ast::LetStmt::cast(parent) {
let field_expr = match let_stmt.initializer()? {
ast::Expr::FieldExpr(field_expr) => field_expr,
_ => return None,
};
self.type_of_expr(&field_expr.expr()?)
} else {
None
}
})
// Binding a reference to a packed type is possibly unsafe.
.map(|ty| ty.is_packed(self.db))
.unwrap_or(false)
self.imp.is_unsafe_bind_pat(bind_pat)
}
}
@ -655,6 +587,86 @@ impl<'db> SemanticsImpl<'db> {
});
InFile::new(file_id, node)
}
pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> bool {
method_call_expr
.expr()
.and_then(|expr| {
let field_expr = if let ast::Expr::FieldExpr(field_expr) = expr {
field_expr
} else {
return None;
};
let ty = self.type_of_expr(&field_expr.expr()?)?;
if !ty.is_packed(self.db) {
return None;
}
let func = self.resolve_method_call(&method_call_expr).map(Function::from)?;
let is_unsafe = func.has_self_param(self.db)
&& matches!(func.params(self.db).first(), Some(TypeRef::Reference(..)));
Some(is_unsafe)
})
.unwrap_or(false)
}
pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
ref_expr
.expr()
.and_then(|expr| {
let field_expr = match expr {
ast::Expr::FieldExpr(field_expr) => field_expr,
_ => return None,
};
let expr = field_expr.expr()?;
self.type_of_expr(&expr)
})
// Binding a reference to a packed type is possibly unsafe.
.map(|ty| ty.is_packed(self.db))
.unwrap_or(false)
// FIXME This needs layout computation to be correct. It will highlight
// more than it should with the current implementation.
}
pub fn is_unsafe_bind_pat(&self, bind_pat: &ast::BindPat) -> bool {
bind_pat
.syntax()
.parent()
.and_then(|parent| {
// `BindPat` can live under `RecordPat` directly under `RecordFieldPat` or
// `RecordFieldPatList`. `RecordFieldPat` also lives under `RecordFieldPatList`,
// so this tries to lookup the `BindPat` anywhere along that structure to the
// `RecordPat` so we can get the containing type.
let record_pat = ast::RecordFieldPat::cast(parent.clone())
.and_then(|record_pat| record_pat.syntax().parent())
.or_else(|| Some(parent.clone()))
.and_then(|parent| {
ast::RecordFieldPatList::cast(parent)?
.syntax()
.parent()
.and_then(ast::RecordPat::cast)
});
// If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if
// this is initialized from a `FieldExpr`.
if let Some(record_pat) = record_pat {
self.type_of_pat(&ast::Pat::RecordPat(record_pat))
} else if let Some(let_stmt) = ast::LetStmt::cast(parent) {
let field_expr = match let_stmt.initializer()? {
ast::Expr::FieldExpr(field_expr) => field_expr,
_ => return None,
};
self.type_of_expr(&field_expr.expr()?)
} else {
None
}
})
// Binding a reference to a packed type is possibly unsafe.
.map(|ty| ty.is_packed(self.db))
.unwrap_or(false)
}
}
pub trait ToDef: AstNode + Clone {