aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists/src/handlers/extract_variable.rs
diff options
context:
space:
mode:
authorVladyslav Katasonov <[email protected]>2021-02-16 20:48:15 +0000
committerAleksey Kladov <[email protected]>2021-03-02 13:25:22 +0000
commitafc68277f69572944fd81d61b126732ab29b5d17 (patch)
tree2ce079a2d48f83cd9520a48c3d6d1082626008fa /crates/ide_assists/src/handlers/extract_variable.rs
parentf915ab79fa1b11982b8e82e2db5b2486a893bed4 (diff)
pull out suggest_name::* to utils; enchance heuristics
Diffstat (limited to 'crates/ide_assists/src/handlers/extract_variable.rs')
-rw-r--r--crates/ide_assists/src/handlers/extract_variable.rs92
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 @@
1use itertools::Itertools; 1use stdx::format_to;
2use stdx::{format_to, to_lower_snake_case};
3use syntax::{ 2use 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};
10use test_utils::mark; 9use test_utils::mark;
11 10
12use crate::{AssistContext, AssistId, AssistKind, Assists}; 11use 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
177fn 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
186fn 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
197fn 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
210fn 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
219fn 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
242fn 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
249fn 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)]
261mod tests { 177mod tests {
262 use test_utils::mark; 178 use test_utils::mark;