mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-14 06:03:58 +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 {
|
pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> bool {
|
||||||
method_call_expr
|
self.imp.is_unsafe_method_call(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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
|
pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
|
||||||
ref_expr
|
self.imp.is_unsafe_ref_expr(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 {
|
pub fn is_unsafe_bind_pat(&self, bind_pat: &ast::BindPat) -> bool {
|
||||||
bind_pat
|
self.imp.is_unsafe_bind_pat(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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,6 +587,86 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
});
|
});
|
||||||
InFile::new(file_id, node)
|
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 {
|
pub trait ToDef: AstNode + Clone {
|
||||||
|
|
Loading…
Reference in a new issue