use syntax::{
ast::{self, make, FieldExpr, MethodCallExpr},
AstNode, T,
};
use crate::AssistContext;
pub(crate) fn determine_ref_and_parens(
ctx: &AssistContext<'_>,
field_expr: &FieldExpr,
) -> (ast::Expr, RefData) {
let s = field_expr.syntax();
let mut ref_data = RefData { needs_deref: true, needs_parentheses: true };
let mut target_node = field_expr.clone().into();
let parent = match s.parent().map(ast::Expr::cast) {
Some(Some(parent)) => parent,
Some(None) => {
ref_data.needs_parentheses = false;
return (target_node, ref_data);
}
None => return (target_node, ref_data),
};
match parent {
ast::Expr::ParenExpr(it) => {
ref_data.needs_parentheses = false;
if let Some(it) = it.syntax().parent().and_then(ast::RefExpr::cast) {
ref_data.needs_deref = false;
target_node = it.into();
}
}
ast::Expr::RefExpr(it) => {
ref_data.needs_deref = false;
ref_data.needs_parentheses = false;
match it.syntax().parent().and_then(ast::ParenExpr::cast) {
Some(parent) => target_node = parent.into(),
None => target_node = it.into(),
};
}
ast::Expr::PathExpr(_it) => {}
ast::Expr::MethodCallExpr(it) => {
fn is_auto_ref(ctx: &AssistContext<'_>, call_expr: &MethodCallExpr) -> bool {
fn impl_(ctx: &AssistContext<'_>, call_expr: &MethodCallExpr) -> Option<bool> {
let rec = call_expr.receiver()?;
let rec_ty = ctx.sema.type_of_expr(&rec)?.original();
if rec_ty.is_reference() {
return Some(false);
}
let f = ctx.sema.resolve_method_call(call_expr)?;
let self_param = f.self_param(ctx.db())?;
match self_param.access(ctx.db()) {
hir::Access::Shared | hir::Access::Exclusive => Some(true),
hir::Access::Owned => Some(false),
}
}
impl_(ctx, call_expr).unwrap_or(false)
}
if is_auto_ref(ctx, &it) {
ref_data.needs_deref = false;
ref_data.needs_parentheses = false;
}
}
ast::Expr::FieldExpr(_it) => {
ref_data.needs_deref = false;
ref_data.needs_parentheses = false;
}
ast::Expr::IndexExpr(_it) => {
ref_data.needs_deref = false;
ref_data.needs_parentheses = false;
}
ast::Expr::TryExpr(_it) => {
}
_ => {
ref_data.needs_parentheses = false;
}
};
(target_node, ref_data)
}
pub(crate) struct RefData {
needs_deref: bool,
needs_parentheses: bool,
}
impl RefData {
pub(crate) fn wrap_expr(&self, mut expr: ast::Expr) -> ast::Expr {
if self.needs_deref {
expr = make::expr_prefix(T![*], expr);
}
if self.needs_parentheses {
expr = make::expr_paren(expr);
}
expr
}
}