@@ -29,22 +29,31 @@ use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists};
29
29
// }
30
30
// ```
31
31
pub ( crate ) fn extract_variable ( acc : & mut Assists , ctx : & AssistContext < ' _ > ) -> Option < ( ) > {
32
- if ctx. has_empty_selection ( ) {
33
- return None ;
34
- }
35
-
36
- let node = match ctx. covering_element ( ) {
37
- NodeOrToken :: Node ( it) => it,
38
- NodeOrToken :: Token ( it) if it. kind ( ) == COMMENT => {
39
- cov_mark:: hit!( extract_var_in_comment_is_not_applicable) ;
32
+ let node = if ctx. has_empty_selection ( ) {
33
+ if let Some ( expr_stmt) = ctx. find_node_at_offset :: < ast:: ExprStmt > ( ) {
34
+ expr_stmt. syntax ( ) . clone ( )
35
+ } else if let Some ( expr) = ctx. find_node_at_offset :: < ast:: Expr > ( ) {
36
+ expr. syntax ( ) . ancestors ( ) . find_map ( valid_target_expr) ?. syntax ( ) . clone ( )
37
+ } else {
40
38
return None ;
41
39
}
42
- NodeOrToken :: Token ( it) => it. parent ( ) ?,
40
+ } else {
41
+ match ctx. covering_element ( ) {
42
+ NodeOrToken :: Node ( it) => it,
43
+ NodeOrToken :: Token ( it) if it. kind ( ) == COMMENT => {
44
+ cov_mark:: hit!( extract_var_in_comment_is_not_applicable) ;
45
+ return None ;
46
+ }
47
+ NodeOrToken :: Token ( it) => it. parent ( ) ?,
48
+ }
43
49
} ;
50
+
44
51
let node = node. ancestors ( ) . take_while ( |anc| anc. text_range ( ) == node. text_range ( ) ) . last ( ) ?;
52
+ let range = node. text_range ( ) ;
53
+
45
54
let to_extract = node
46
55
. descendants ( )
47
- . take_while ( |it| ctx . selection_trimmed ( ) . contains_range ( it. text_range ( ) ) )
56
+ . take_while ( |it| range . contains_range ( it. text_range ( ) ) )
48
57
. find_map ( valid_target_expr) ?;
49
58
50
59
let ty = ctx. sema . type_of_expr ( & to_extract) . map ( TypeInfo :: adjusted) ;
@@ -235,6 +244,138 @@ mod tests {
235
244
236
245
use super :: * ;
237
246
247
+ #[ test]
248
+ fn test_extract_var_simple_without_select ( ) {
249
+ check_assist (
250
+ extract_variable,
251
+ r#"
252
+ fn main() -> i32 {
253
+ if true {
254
+ 1
255
+ } else {
256
+ 2
257
+ }$0
258
+ }
259
+ "# ,
260
+ r#"
261
+ fn main() -> i32 {
262
+ let $0var_name = if true {
263
+ 1
264
+ } else {
265
+ 2
266
+ };
267
+ var_name
268
+ }
269
+ "# ,
270
+ ) ;
271
+
272
+ check_assist (
273
+ extract_variable,
274
+ r#"
275
+ fn foo() -> i32 { 1 }
276
+ fn main() {
277
+ foo();$0
278
+ }
279
+ "# ,
280
+ r#"
281
+ fn foo() -> i32 { 1 }
282
+ fn main() {
283
+ let $0foo = foo();
284
+ }
285
+ "# ,
286
+ ) ;
287
+
288
+ check_assist (
289
+ extract_variable,
290
+ r#"
291
+ fn main() {
292
+ let a = Some(2);
293
+ a.is_some();$0
294
+ }
295
+ "# ,
296
+ r#"
297
+ fn main() {
298
+ let a = Some(2);
299
+ let $0is_some = a.is_some();
300
+ }
301
+ "# ,
302
+ ) ;
303
+
304
+ check_assist (
305
+ extract_variable,
306
+ r#"
307
+ fn main() {
308
+ "hello"$0;
309
+ }
310
+ "# ,
311
+ r#"
312
+ fn main() {
313
+ let $0var_name = "hello";
314
+ }
315
+ "# ,
316
+ ) ;
317
+
318
+ check_assist (
319
+ extract_variable,
320
+ r#"
321
+ fn main() {
322
+ 1 + 2$0;
323
+ }
324
+ "# ,
325
+ r#"
326
+ fn main() {
327
+ let $0var_name = 1 + 2;
328
+ }
329
+ "# ,
330
+ ) ;
331
+
332
+ check_assist (
333
+ extract_variable,
334
+ r#"
335
+ fn main() {
336
+ match () {
337
+ () if true => 1,
338
+ _ => 2,
339
+ };$0
340
+ }
341
+ "# ,
342
+ r#"
343
+ fn main() {
344
+ let $0var_name = match () {
345
+ () if true => 1,
346
+ _ => 2,
347
+ };
348
+ }
349
+ "# ,
350
+ ) ;
351
+ }
352
+
353
+ #[ test]
354
+ fn test_extract_var_unit_expr_without_select_not_applicable ( ) {
355
+ check_assist_not_applicable (
356
+ extract_variable,
357
+ r#"
358
+ fn foo() {}
359
+ fn main() {
360
+ foo()$0;
361
+ }
362
+ "# ,
363
+ ) ;
364
+
365
+ check_assist_not_applicable (
366
+ extract_variable,
367
+ r#"
368
+ fn foo() {
369
+ let mut i = 3;
370
+ if i >= 0 {
371
+ i += 1;
372
+ } else {
373
+ i -= 1;
374
+ }$0
375
+ }"# ,
376
+ ) ;
377
+ }
378
+
238
379
#[ test]
239
380
fn test_extract_var_simple ( ) {
240
381
check_assist (
0 commit comments