mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Move unsafe semantics methods into SemanticsImpl
and reference them in Semantics
This commit is contained in:
parent
39fdd41df4
commit
61dff939f9
1 changed files with 83 additions and 71 deletions
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue