ide_assists/utils/
ref_field_expr.rs1use syntax::{
7 AstNode, T,
8 ast::{self, FieldExpr, MethodCallExpr, syntax_factory::SyntaxFactory},
9};
10
11use crate::AssistContext;
12
13pub(crate) fn determine_ref_and_parens(
16 ctx: &AssistContext<'_, '_>,
17 field_expr: &FieldExpr,
18) -> (ast::Expr, RefData) {
19 let s = field_expr.syntax();
20 let mut ref_data = RefData { needs_deref: true, needs_parentheses: true };
21 let mut target_node = field_expr.clone().into();
22
23 let parent = match s.parent().map(ast::Expr::cast) {
24 Some(Some(parent)) => parent,
25 Some(None) => {
26 ref_data.needs_parentheses = false;
27 return (target_node, ref_data);
28 }
29 None => return (target_node, ref_data),
30 };
31
32 match parent {
33 ast::Expr::ParenExpr(it) => {
34 ref_data.needs_parentheses = false;
36 if let Some(it) = it.syntax().parent().and_then(ast::RefExpr::cast) {
38 ref_data.needs_deref = false;
39 target_node = it.into();
40 }
41 }
42 ast::Expr::RefExpr(it) => {
43 ref_data.needs_deref = false;
45 ref_data.needs_parentheses = false;
46 match it.syntax().parent().and_then(ast::ParenExpr::cast) {
48 Some(parent) => target_node = parent.into(),
49 None => target_node = it.into(),
50 };
51 }
52 ast::Expr::PathExpr(_it) => {}
56 ast::Expr::MethodCallExpr(it) => {
57 fn is_auto_ref(ctx: &AssistContext<'_, '_>, call_expr: &MethodCallExpr) -> bool {
66 fn impl_(ctx: &AssistContext<'_, '_>, call_expr: &MethodCallExpr) -> Option<bool> {
67 let rec = call_expr.receiver()?;
68 let rec_ty = ctx.sema.type_of_expr(&rec)?.original();
69 if rec_ty.is_reference() {
71 return Some(false);
72 }
73
74 let f = ctx.sema.resolve_method_call(call_expr)?;
76 let self_param = f.self_param(ctx.db())?;
77 match self_param.access(ctx.db()) {
79 hir::Access::Shared | hir::Access::Exclusive => Some(true),
80 hir::Access::Owned => Some(false),
81 }
82 }
83 impl_(ctx, call_expr).unwrap_or(false)
84 }
85
86 if is_auto_ref(ctx, &it) {
87 ref_data.needs_deref = false;
88 ref_data.needs_parentheses = false;
89 }
90 }
91 ast::Expr::FieldExpr(_it) => {
92 ref_data.needs_deref = false;
94 ref_data.needs_parentheses = false;
95 }
96 ast::Expr::IndexExpr(_it) => {
97 ref_data.needs_deref = false;
99 ref_data.needs_parentheses = false;
100 }
101 ast::Expr::TryExpr(_it) => {
102 }
105 _ => {
107 ref_data.needs_parentheses = false;
108 }
109 };
110
111 (target_node, ref_data)
112}
113
114pub(crate) struct RefData {
116 needs_deref: bool,
117 needs_parentheses: bool,
118}
119
120impl RefData {
121 pub(crate) fn wrap_expr(&self, mut expr: ast::Expr, make: &SyntaxFactory) -> ast::Expr {
123 if self.needs_deref {
124 expr = make.expr_prefix(T![*], expr).into();
125 }
126
127 if self.needs_parentheses {
128 expr = make.expr_paren(expr).into();
129 }
130
131 expr
132 }
133
134 pub(crate) fn wrap_expr_with_factory(
135 &self,
136 mut expr: ast::Expr,
137 syntax_factory: &SyntaxFactory,
138 ) -> ast::Expr {
139 if self.needs_deref {
140 expr = syntax_factory.expr_prefix(T![*], expr).into();
141 }
142
143 if self.needs_parentheses {
144 expr = syntax_factory.expr_paren(expr).into();
145 }
146
147 expr
148 }
149}