diff options
| author | Vladyslav Katasonov <[email protected]> | 2021-02-16 21:42:58 +0000 |
|---|---|---|
| committer | Aleksey Kladov <[email protected]> | 2021-03-02 13:25:24 +0000 |
| commit | 7066e6b3620d06dbc2143b9dfdda4d7c97d6a8ba (patch) | |
| tree | ccfc2aa51bc29e0828c381ad5549098f18fb5114 /crates/ide_assists/src/utils | |
| parent | afc68277f69572944fd81d61b126732ab29b5d17 (diff) | |
strip useless methods, and unary ops in suggest_name
Diffstat (limited to 'crates/ide_assists/src/utils')
| -rw-r--r-- | crates/ide_assists/src/utils/suggest_name.rs | 121 |
1 files changed, 114 insertions, 7 deletions
diff --git a/crates/ide_assists/src/utils/suggest_name.rs b/crates/ide_assists/src/utils/suggest_name.rs index 345e9af40..d37c62642 100644 --- a/crates/ide_assists/src/utils/suggest_name.rs +++ b/crates/ide_assists/src/utils/suggest_name.rs | |||
| @@ -29,6 +29,29 @@ const WRAPPER_TYPES: &[&str] = &["Box", "Option", "Result"]; | |||
| 29 | /// `args.into_config()` -> `config` | 29 | /// `args.into_config()` -> `config` |
| 30 | /// `bytes.to_vec()` -> `vec` | 30 | /// `bytes.to_vec()` -> `vec` |
| 31 | const USELESS_METHOD_PREFIXES: &[&str] = &["into_", "as_", "to_"]; | 31 | const USELESS_METHOD_PREFIXES: &[&str] = &["into_", "as_", "to_"]; |
| 32 | /// Useless methods that are stripped from expression | ||
| 33 | /// | ||
| 34 | /// # Examples | ||
| 35 | /// `var.name().to_string()` -> `var.name()` | ||
| 36 | const USELESS_METHODS: &[&str] = &[ | ||
| 37 | "to_string", | ||
| 38 | "as_str", | ||
| 39 | "to_owned", | ||
| 40 | "as_ref", | ||
| 41 | "clone", | ||
| 42 | "cloned", | ||
| 43 | "expect", | ||
| 44 | "expect_none", | ||
| 45 | "unwrap", | ||
| 46 | "unwrap_none", | ||
| 47 | "unwrap_or", | ||
| 48 | "unwrap_or_default", | ||
| 49 | "unwrap_or_else", | ||
| 50 | "unwrap_unchecked", | ||
| 51 | "iter", | ||
| 52 | "into_iter", | ||
| 53 | "iter_mut", | ||
| 54 | ]; | ||
| 32 | 55 | ||
| 33 | /// Suggest name of variable for given expression | 56 | /// Suggest name of variable for given expression |
| 34 | /// | 57 | /// |
| @@ -49,10 +72,39 @@ const USELESS_METHOD_PREFIXES: &[&str] = &["into_", "as_", "to_"]; | |||
| 49 | /// | 72 | /// |
| 50 | /// Currently it sticks to the first name found. | 73 | /// Currently it sticks to the first name found. |
| 51 | pub(crate) fn variable(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> String { | 74 | pub(crate) fn variable(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> String { |
| 52 | from_param(expr, sema) | 75 | // `from_param` does not benifit from stripping |
| 53 | .or_else(|| from_call(expr)) | 76 | // it need the largest context possible |
| 54 | .or_else(|| from_type(expr, sema)) | 77 | // so we check firstmost |
| 55 | .unwrap_or_else(|| "var_name".to_string()) | 78 | if let Some(name) = from_param(expr, sema) { |
| 79 | return name; | ||
| 80 | } | ||
| 81 | |||
| 82 | let mut next_expr = Some(expr.clone()); | ||
| 83 | while let Some(expr) = next_expr { | ||
| 84 | let name = from_call(&expr).or_else(|| from_type(&expr, sema)); | ||
| 85 | if let Some(name) = name { | ||
| 86 | return name; | ||
| 87 | } | ||
| 88 | |||
| 89 | match expr { | ||
| 90 | ast::Expr::RefExpr(inner) => next_expr = inner.expr(), | ||
| 91 | ast::Expr::BoxExpr(inner) => next_expr = inner.expr(), | ||
| 92 | ast::Expr::AwaitExpr(inner) => next_expr = inner.expr(), | ||
| 93 | // ast::Expr::BlockExpr(block) => expr = block.tail_expr(), | ||
| 94 | ast::Expr::CastExpr(inner) => next_expr = inner.expr(), | ||
| 95 | ast::Expr::MethodCallExpr(method) if is_useless_method(&method) => { | ||
| 96 | next_expr = method.receiver(); | ||
| 97 | } | ||
| 98 | ast::Expr::ParenExpr(inner) => next_expr = inner.expr(), | ||
| 99 | ast::Expr::TryExpr(inner) => next_expr = inner.expr(), | ||
| 100 | ast::Expr::PrefixExpr(prefix) if prefix.op_kind() == Some(ast::PrefixOp::Deref) => { | ||
| 101 | next_expr = prefix.expr() | ||
| 102 | } | ||
| 103 | _ => break, | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | "var_name".to_string() | ||
| 56 | } | 108 | } |
| 57 | 109 | ||
| 58 | fn normalize(name: &str) -> Option<String> { | 110 | fn normalize(name: &str) -> Option<String> { |
| @@ -76,6 +128,16 @@ fn is_valid_name(name: &str) -> bool { | |||
| 76 | } | 128 | } |
| 77 | } | 129 | } |
| 78 | 130 | ||
| 131 | fn is_useless_method(method: &ast::MethodCallExpr) -> bool { | ||
| 132 | let ident = method.name_ref().and_then(|it| it.ident_token()); | ||
| 133 | |||
| 134 | if let Some(ident) = ident { | ||
| 135 | USELESS_METHODS.contains(&ident.text()) | ||
| 136 | } else { | ||
| 137 | false | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 79 | fn from_call(expr: &ast::Expr) -> Option<String> { | 141 | fn from_call(expr: &ast::Expr) -> Option<String> { |
| 80 | from_func_call(expr).or_else(|| from_method_call(expr)) | 142 | from_func_call(expr).or_else(|| from_method_call(expr)) |
| 81 | } | 143 | } |
| @@ -99,15 +161,20 @@ fn from_method_call(expr: &ast::Expr) -> Option<String> { | |||
| 99 | _ => return None, | 161 | _ => return None, |
| 100 | }; | 162 | }; |
| 101 | let ident = method.name_ref()?.ident_token()?; | 163 | let ident = method.name_ref()?.ident_token()?; |
| 102 | let name = normalize(ident.text())?; | 164 | let mut name = ident.text(); |
| 165 | |||
| 166 | if USELESS_METHODS.contains(&name) { | ||
| 167 | return None; | ||
| 168 | } | ||
| 103 | 169 | ||
| 104 | for prefix in USELESS_METHOD_PREFIXES { | 170 | for prefix in USELESS_METHOD_PREFIXES { |
| 105 | if let Some(suffix) = name.strip_prefix(prefix) { | 171 | if let Some(suffix) = name.strip_prefix(prefix) { |
| 106 | return Some(suffix.to_string()); | 172 | name = suffix; |
| 173 | break; | ||
| 107 | } | 174 | } |
| 108 | } | 175 | } |
| 109 | 176 | ||
| 110 | Some(name) | 177 | normalize(&name) |
| 111 | } | 178 | } |
| 112 | 179 | ||
| 113 | fn from_param(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option<String> { | 180 | fn from_param(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option<String> { |
| @@ -767,4 +834,44 @@ mod tests { | |||
| 767 | ); | 834 | ); |
| 768 | } | 835 | } |
| 769 | } | 836 | } |
| 837 | |||
| 838 | mod variable { | ||
| 839 | use super::*; | ||
| 840 | |||
| 841 | #[test] | ||
| 842 | fn ref_call() { | ||
| 843 | check_name_suggestion( | ||
| 844 | |e, c| Some(variable(e, c)), | ||
| 845 | r#" | ||
| 846 | fn foo() { | ||
| 847 | $0&bar(1, 3)$0 | ||
| 848 | }"#, | ||
| 849 | "bar", | ||
| 850 | ); | ||
| 851 | } | ||
| 852 | |||
| 853 | #[test] | ||
| 854 | fn name_to_string() { | ||
| 855 | check_name_suggestion( | ||
| 856 | |e, c| Some(variable(e, c)), | ||
| 857 | r#" | ||
| 858 | fn foo() { | ||
| 859 | $0function.name().to_string()$0 | ||
| 860 | }"#, | ||
| 861 | "name", | ||
| 862 | ); | ||
| 863 | } | ||
| 864 | |||
| 865 | #[test] | ||
| 866 | fn nested_useless_method() { | ||
| 867 | check_name_suggestion( | ||
| 868 | |e, c| Some(variable(e, c)), | ||
| 869 | r#" | ||
| 870 | fn foo() { | ||
| 871 | $0function.name().as_ref().unwrap().to_string()$0 | ||
| 872 | }"#, | ||
| 873 | "name", | ||
| 874 | ); | ||
| 875 | } | ||
| 876 | } | ||
| 770 | } | 877 | } |
