@@ -29,6 +29,29 @@ const WRAPPER_TYPES: &[&str] = &["Box", "Option", "Result"];
29
29
/// `args.into_config()` -> `config`
30
30
/// `bytes.to_vec()` -> `vec`
31
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
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
73
/// Currently it sticks to the first name found.
51
74
pub ( crate ) fn variable ( expr : & ast:: Expr , sema : & Semantics < ' _ , RootDatabase > ) -> String {
52
- from_param ( expr, sema)
53
- . or_else ( || from_call ( expr) )
54
- . or_else ( || from_type ( expr, sema) )
55
- . unwrap_or_else ( || "var_name" . to_string ( ) )
75
+ // `from_param` does not benifit from stripping
76
+ // it need the largest context possible
77
+ // so we check firstmost
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
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
141
fn from_call ( expr : & ast:: Expr ) -> Option < String > {
80
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
161
_ => return None ,
100
162
} ;
101
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
170
for prefix in USELESS_METHOD_PREFIXES {
105
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
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
}
0 commit comments