diff options
author | Vladyslav Katasonov <[email protected]> | 2021-02-16 20:48:15 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2021-03-02 13:25:22 +0000 |
commit | afc68277f69572944fd81d61b126732ab29b5d17 (patch) | |
tree | 2ce079a2d48f83cd9520a48c3d6d1082626008fa /crates/ide_assists/src/handlers | |
parent | f915ab79fa1b11982b8e82e2db5b2486a893bed4 (diff) |
pull out suggest_name::* to utils; enchance heuristics
Diffstat (limited to 'crates/ide_assists/src/handlers')
-rw-r--r-- | crates/ide_assists/src/handlers/extract_variable.rs | 92 |
1 files changed, 4 insertions, 88 deletions
diff --git a/crates/ide_assists/src/handlers/extract_variable.rs b/crates/ide_assists/src/handlers/extract_variable.rs index 2c47be987..312ac7ac4 100644 --- a/crates/ide_assists/src/handlers/extract_variable.rs +++ b/crates/ide_assists/src/handlers/extract_variable.rs | |||
@@ -1,7 +1,6 @@ | |||
1 | use itertools::Itertools; | 1 | use stdx::format_to; |
2 | use stdx::{format_to, to_lower_snake_case}; | ||
3 | use syntax::{ | 2 | use syntax::{ |
4 | ast::{self, AstNode, NameOwner}, | 3 | ast::{self, AstNode}, |
5 | SyntaxKind::{ | 4 | SyntaxKind::{ |
6 | BLOCK_EXPR, BREAK_EXPR, CLOSURE_EXPR, COMMENT, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR, | 5 | BLOCK_EXPR, BREAK_EXPR, CLOSURE_EXPR, COMMENT, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR, |
7 | }, | 6 | }, |
@@ -9,7 +8,7 @@ use syntax::{ | |||
9 | }; | 8 | }; |
10 | use test_utils::mark; | 9 | use test_utils::mark; |
11 | 10 | ||
12 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 11 | use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists}; |
13 | 12 | ||
14 | // Assist: extract_variable | 13 | // Assist: extract_variable |
15 | // | 14 | // |
@@ -55,7 +54,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
55 | 54 | ||
56 | let var_name = match &field_shorthand { | 55 | let var_name = match &field_shorthand { |
57 | Some(it) => it.to_string(), | 56 | Some(it) => it.to_string(), |
58 | None => suggest_variable_name(ctx, &to_extract), | 57 | None => suggest_name::variable(&to_extract, &ctx.sema), |
59 | }; | 58 | }; |
60 | let expr_range = match &field_shorthand { | 59 | let expr_range = match &field_shorthand { |
61 | Some(it) => it.syntax().text_range().cover(to_extract.syntax().text_range()), | 60 | Some(it) => it.syntax().text_range().cover(to_extract.syntax().text_range()), |
@@ -174,89 +173,6 @@ impl Anchor { | |||
174 | } | 173 | } |
175 | } | 174 | } |
176 | 175 | ||
177 | fn suggest_variable_name(ctx: &AssistContext, expr: &ast::Expr) -> String { | ||
178 | // FIXME: account for existing names in the scope | ||
179 | suggest_name_from_param(ctx, expr) | ||
180 | .or_else(|| suggest_name_from_func(expr)) | ||
181 | .or_else(|| suggest_name_from_method(expr)) | ||
182 | .or_else(|| suggest_name_by_type(ctx, expr)) | ||
183 | .unwrap_or_else(|| "var_name".to_string()) | ||
184 | } | ||
185 | |||
186 | fn normalize_name(name: &str) -> Option<String> { | ||
187 | let name = to_lower_snake_case(name); | ||
188 | |||
189 | let useless_names = ["new", "default", "some", "none", "ok", "err"]; | ||
190 | if useless_names.contains(&name.as_str()) { | ||
191 | return None; | ||
192 | } | ||
193 | |||
194 | Some(name) | ||
195 | } | ||
196 | |||
197 | fn suggest_name_from_func(expr: &ast::Expr) -> Option<String> { | ||
198 | let call = match expr { | ||
199 | ast::Expr::CallExpr(call) => call, | ||
200 | _ => return None, | ||
201 | }; | ||
202 | let func = match call.expr()? { | ||
203 | ast::Expr::PathExpr(path) => path, | ||
204 | _ => return None, | ||
205 | }; | ||
206 | let ident = func.path()?.segment()?.name_ref()?.ident_token()?; | ||
207 | normalize_name(ident.text()) | ||
208 | } | ||
209 | |||
210 | fn suggest_name_from_method(expr: &ast::Expr) -> Option<String> { | ||
211 | let method = match expr { | ||
212 | ast::Expr::MethodCallExpr(call) => call, | ||
213 | _ => return None, | ||
214 | }; | ||
215 | let ident = method.name_ref()?.ident_token()?; | ||
216 | normalize_name(ident.text()) | ||
217 | } | ||
218 | |||
219 | fn suggest_name_from_param(ctx: &AssistContext, expr: &ast::Expr) -> Option<String> { | ||
220 | let arg_list = expr.syntax().parent().and_then(ast::ArgList::cast)?; | ||
221 | let args_parent = arg_list.syntax().parent()?; | ||
222 | let func = if let Some(call) = ast::CallExpr::cast(args_parent.clone()) { | ||
223 | let func = call.expr()?; | ||
224 | let func_ty = ctx.sema.type_of_expr(&func)?; | ||
225 | func_ty.as_callable(ctx.db())? | ||
226 | } else if let Some(method) = ast::MethodCallExpr::cast(args_parent) { | ||
227 | ctx.sema.resolve_method_call_as_callable(&method)? | ||
228 | } else { | ||
229 | return None; | ||
230 | }; | ||
231 | |||
232 | let (idx, _) = arg_list.args().find_position(|it| it == expr).unwrap(); | ||
233 | let (pat, _) = func.params(ctx.db()).into_iter().nth(idx)?; | ||
234 | let param = match pat? { | ||
235 | either::Either::Right(ast::Pat::IdentPat(param)) => param, | ||
236 | _ => return None, | ||
237 | }; | ||
238 | let name = param.name()?; | ||
239 | normalize_name(&name.to_string()) | ||
240 | } | ||
241 | |||
242 | fn suggest_name_by_type(ctx: &AssistContext, expr: &ast::Expr) -> Option<String> { | ||
243 | let ty = ctx.sema.type_of_expr(expr)?; | ||
244 | let ty = ty.remove_ref().unwrap_or(ty); | ||
245 | |||
246 | name_from_type(ty, ctx) | ||
247 | } | ||
248 | |||
249 | fn name_from_type(ty: hir::Type, ctx: &AssistContext) -> Option<String> { | ||
250 | let name = if let Some(adt) = ty.as_adt() { | ||
251 | adt.name(ctx.db()).to_string() | ||
252 | } else if let Some(trait_) = ty.as_dyn_trait() { | ||
253 | trait_.name(ctx.db()).to_string() | ||
254 | } else { | ||
255 | return None; | ||
256 | }; | ||
257 | normalize_name(&name) | ||
258 | } | ||
259 | |||
260 | #[cfg(test)] | 176 | #[cfg(test)] |
261 | mod tests { | 177 | mod tests { |
262 | use test_utils::mark; | 178 | use test_utils::mark; |