]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/ide/src/move_item.rs
Rollup merge of #99614 - RalfJung:transmute-is-not-memcpy, r=thomcc
[rust.git] / src / tools / rust-analyzer / crates / ide / src / move_item.rs
1 use std::{iter::once, mem};
2
3 use hir::Semantics;
4 use ide_db::{base_db::FileRange, helpers::pick_best_token, RootDatabase};
5 use itertools::Itertools;
6 use syntax::{algo, ast, match_ast, AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange};
7 use text_edit::{TextEdit, TextEditBuilder};
8
9 #[derive(Copy, Clone, Debug)]
10 pub enum Direction {
11     Up,
12     Down,
13 }
14
15 // Feature: Move Item
16 //
17 // Move item under cursor or selection up and down.
18 //
19 // |===
20 // | Editor  | Action Name
21 //
22 // | VS Code | **Rust Analyzer: Move item up**
23 // | VS Code | **Rust Analyzer: Move item down**
24 // |===
25 //
26 // image::https://user-images.githubusercontent.com/48062697/113065576-04298180-91b1-11eb-91ce-4505e99ed598.gif[]
27 pub(crate) fn move_item(
28     db: &RootDatabase,
29     range: FileRange,
30     direction: Direction,
31 ) -> Option<TextEdit> {
32     let sema = Semantics::new(db);
33     let file = sema.parse(range.file_id);
34
35     let item = if range.range.is_empty() {
36         SyntaxElement::Token(pick_best_token(
37             file.syntax().token_at_offset(range.range.start()),
38             |kind| match kind {
39                 SyntaxKind::IDENT | SyntaxKind::LIFETIME_IDENT => 2,
40                 kind if kind.is_trivia() => 0,
41                 _ => 1,
42             },
43         )?)
44     } else {
45         file.syntax().covering_element(range.range)
46     };
47
48     find_ancestors(item, direction, range.range)
49 }
50
51 fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -> Option<TextEdit> {
52     let root = match item {
53         SyntaxElement::Node(node) => node,
54         SyntaxElement::Token(token) => token.parent()?,
55     };
56
57     let movable = [
58         SyntaxKind::ARG_LIST,
59         SyntaxKind::GENERIC_PARAM_LIST,
60         SyntaxKind::GENERIC_ARG_LIST,
61         SyntaxKind::VARIANT_LIST,
62         SyntaxKind::TYPE_BOUND_LIST,
63         SyntaxKind::MATCH_ARM,
64         SyntaxKind::PARAM,
65         SyntaxKind::LET_STMT,
66         SyntaxKind::EXPR_STMT,
67         SyntaxKind::IF_EXPR,
68         SyntaxKind::FOR_EXPR,
69         SyntaxKind::LOOP_EXPR,
70         SyntaxKind::WHILE_EXPR,
71         SyntaxKind::RETURN_EXPR,
72         SyntaxKind::MATCH_EXPR,
73         SyntaxKind::MACRO_CALL,
74         SyntaxKind::TYPE_ALIAS,
75         SyntaxKind::TRAIT,
76         SyntaxKind::IMPL,
77         SyntaxKind::MACRO_DEF,
78         SyntaxKind::STRUCT,
79         SyntaxKind::UNION,
80         SyntaxKind::ENUM,
81         SyntaxKind::FN,
82         SyntaxKind::MODULE,
83         SyntaxKind::USE,
84         SyntaxKind::STATIC,
85         SyntaxKind::CONST,
86         SyntaxKind::MACRO_RULES,
87         SyntaxKind::MACRO_DEF,
88     ];
89
90     let ancestor = once(root.clone())
91         .chain(root.ancestors())
92         .find(|ancestor| movable.contains(&ancestor.kind()))?;
93
94     move_in_direction(&ancestor, direction, range)
95 }
96
97 fn move_in_direction(
98     node: &SyntaxNode,
99     direction: Direction,
100     range: TextRange,
101 ) -> Option<TextEdit> {
102     match_ast! {
103         match node {
104             ast::ArgList(it) => swap_sibling_in_list(node, it.args(), range, direction),
105             ast::GenericParamList(it) => swap_sibling_in_list(node, it.generic_params(), range, direction),
106             ast::GenericArgList(it) => swap_sibling_in_list(node, it.generic_args(), range, direction),
107             ast::VariantList(it) => swap_sibling_in_list(node, it.variants(), range, direction),
108             ast::TypeBoundList(it) => swap_sibling_in_list(node, it.bounds(), range, direction),
109             _ => Some(replace_nodes(range, node, &match direction {
110                 Direction::Up => node.prev_sibling(),
111                 Direction::Down => node.next_sibling(),
112             }?))
113         }
114     }
115 }
116
117 fn swap_sibling_in_list<A: AstNode + Clone, I: Iterator<Item = A>>(
118     node: &SyntaxNode,
119     list: I,
120     range: TextRange,
121     direction: Direction,
122 ) -> Option<TextEdit> {
123     let list_lookup = list.tuple_windows().find(|(l, r)| match direction {
124         Direction::Up => r.syntax().text_range().contains_range(range),
125         Direction::Down => l.syntax().text_range().contains_range(range),
126     });
127
128     if let Some((l, r)) = list_lookup {
129         Some(replace_nodes(range, l.syntax(), r.syntax()))
130     } else {
131         // Cursor is beyond any movable list item (for example, on curly brace in enum).
132         // It's not necessary, that parent of list is movable (arg list's parent is not, for example),
133         // and we have to continue tree traversal to find suitable node.
134         find_ancestors(SyntaxElement::Node(node.parent()?), direction, range)
135     }
136 }
137
138 fn replace_nodes<'a>(
139     range: TextRange,
140     mut first: &'a SyntaxNode,
141     mut second: &'a SyntaxNode,
142 ) -> TextEdit {
143     let cursor_offset = if range.is_empty() {
144         // FIXME: `applySnippetTextEdits` does not support non-empty selection ranges
145         if first.text_range().contains_range(range) {
146             Some(range.start() - first.text_range().start())
147         } else if second.text_range().contains_range(range) {
148             mem::swap(&mut first, &mut second);
149             Some(range.start() - first.text_range().start())
150         } else {
151             None
152         }
153     } else {
154         None
155     };
156
157     let first_with_cursor = match cursor_offset {
158         Some(offset) => {
159             let mut item_text = first.text().to_string();
160             item_text.insert_str(offset.into(), "$0");
161             item_text
162         }
163         None => first.text().to_string(),
164     };
165
166     let mut edit = TextEditBuilder::default();
167
168     algo::diff(first, second).into_text_edit(&mut edit);
169     edit.replace(second.text_range(), first_with_cursor);
170
171     edit.finish()
172 }
173
174 #[cfg(test)]
175 mod tests {
176     use crate::fixture;
177     use expect_test::{expect, Expect};
178
179     use crate::Direction;
180
181     fn check(ra_fixture: &str, expect: Expect, direction: Direction) {
182         let (analysis, range) = fixture::range(ra_fixture);
183         let edit = analysis.move_item(range, direction).unwrap().unwrap_or_default();
184         let mut file = analysis.file_text(range.file_id).unwrap().to_string();
185         edit.apply(&mut file);
186         expect.assert_eq(&file);
187     }
188
189     #[test]
190     fn test_moves_match_arm_up() {
191         check(
192             r#"
193 fn main() {
194     match true {
195         true => {
196             println!("Hello, world");
197         },
198         false =>$0$0 {
199             println!("Test");
200         }
201     };
202 }
203 "#,
204             expect![[r#"
205                 fn main() {
206                     match true {
207                         false =>$0 {
208                             println!("Test");
209                         }
210                         true => {
211                             println!("Hello, world");
212                         },
213                     };
214                 }
215             "#]],
216             Direction::Up,
217         );
218     }
219
220     #[test]
221     fn test_moves_match_arm_down() {
222         check(
223             r#"
224 fn main() {
225     match true {
226         true =>$0$0 {
227             println!("Hello, world");
228         },
229         false => {
230             println!("Test");
231         }
232     };
233 }
234 "#,
235             expect![[r#"
236                 fn main() {
237                     match true {
238                         false => {
239                             println!("Test");
240                         }
241                         true =>$0 {
242                             println!("Hello, world");
243                         },
244                     };
245                 }
246             "#]],
247             Direction::Down,
248         );
249     }
250
251     #[test]
252     fn test_nowhere_to_move() {
253         check(
254             r#"
255 fn main() {
256     match true {
257         true =>$0$0 {
258             println!("Hello, world");
259         },
260         false => {
261             println!("Test");
262         }
263     };
264 }
265 "#,
266             expect![[r#"
267                 fn main() {
268                     match true {
269                         true => {
270                             println!("Hello, world");
271                         },
272                         false => {
273                             println!("Test");
274                         }
275                     };
276                 }
277             "#]],
278             Direction::Up,
279         );
280     }
281
282     #[test]
283     fn test_moves_let_stmt_up() {
284         check(
285             r#"
286 fn main() {
287     let test = 123;
288     let test2$0$0 = 456;
289 }
290 "#,
291             expect![[r#"
292                 fn main() {
293                     let test2$0 = 456;
294                     let test = 123;
295                 }
296             "#]],
297             Direction::Up,
298         );
299     }
300
301     #[test]
302     fn test_moves_expr_up() {
303         check(
304             r#"
305 fn main() {
306     println!("Hello, world");
307     println!("All I want to say is...");$0$0
308 }
309 "#,
310             expect![[r#"
311                 fn main() {
312                     println!("All I want to say is...");$0
313                     println!("Hello, world");
314                 }
315             "#]],
316             Direction::Up,
317         );
318         check(
319             r#"
320 fn main() {
321     println!("Hello, world");
322
323     if true {
324         println!("Test");
325     }$0$0
326 }
327 "#,
328             expect![[r#"
329                 fn main() {
330                     if true {
331                         println!("Test");
332                     }$0
333
334                     println!("Hello, world");
335                 }
336             "#]],
337             Direction::Up,
338         );
339         check(
340             r#"
341 fn main() {
342     println!("Hello, world");
343
344     for i in 0..10 {
345         println!("Test");
346     }$0$0
347 }
348 "#,
349             expect![[r#"
350                 fn main() {
351                     for i in 0..10 {
352                         println!("Test");
353                     }$0
354
355                     println!("Hello, world");
356                 }
357             "#]],
358             Direction::Up,
359         );
360         check(
361             r#"
362 fn main() {
363     println!("Hello, world");
364
365     loop {
366         println!("Test");
367     }$0$0
368 }
369 "#,
370             expect![[r#"
371                 fn main() {
372                     loop {
373                         println!("Test");
374                     }$0
375
376                     println!("Hello, world");
377                 }
378             "#]],
379             Direction::Up,
380         );
381         check(
382             r#"
383 fn main() {
384     println!("Hello, world");
385
386     while true {
387         println!("Test");
388     }$0$0
389 }
390 "#,
391             expect![[r#"
392                 fn main() {
393                     while true {
394                         println!("Test");
395                     }$0
396
397                     println!("Hello, world");
398                 }
399             "#]],
400             Direction::Up,
401         );
402         check(
403             r#"
404 fn main() {
405     println!("Hello, world");
406
407     return 123;$0$0
408 }
409 "#,
410             expect![[r#"
411                 fn main() {
412                     return 123;$0
413
414                     println!("Hello, world");
415                 }
416             "#]],
417             Direction::Up,
418         );
419     }
420
421     #[test]
422     fn test_nowhere_to_move_stmt() {
423         check(
424             r#"
425 fn main() {
426     println!("All I want to say is...");$0$0
427     println!("Hello, world");
428 }
429 "#,
430             expect![[r#"
431                 fn main() {
432                     println!("All I want to say is...");
433                     println!("Hello, world");
434                 }
435             "#]],
436             Direction::Up,
437         );
438     }
439
440     #[test]
441     fn test_move_item() {
442         check(
443             r#"
444 fn main() {}
445
446 fn foo() {}$0$0
447 "#,
448             expect![[r#"
449                 fn foo() {}$0
450
451                 fn main() {}
452             "#]],
453             Direction::Up,
454         );
455     }
456
457     #[test]
458     fn test_move_impl_up() {
459         check(
460             r#"
461 struct Yay;
462
463 trait Wow {}
464
465 impl Wow for Yay $0$0{}
466 "#,
467             expect![[r#"
468                 struct Yay;
469
470                 impl Wow for Yay $0{}
471
472                 trait Wow {}
473             "#]],
474             Direction::Up,
475         );
476     }
477
478     #[test]
479     fn test_move_use_up() {
480         check(
481             r#"
482 use std::vec::Vec;
483 use std::collections::HashMap$0$0;
484 "#,
485             expect![[r#"
486                 use std::collections::HashMap$0;
487                 use std::vec::Vec;
488             "#]],
489             Direction::Up,
490         );
491     }
492
493     #[test]
494     fn test_moves_match_expr_up() {
495         check(
496             r#"
497 fn main() {
498     let test = 123;
499
500     $0match test {
501         456 => {},
502         _ => {}
503     };$0
504 }
505 "#,
506             expect![[r#"
507                 fn main() {
508                     match test {
509                         456 => {},
510                         _ => {}
511                     };
512
513                     let test = 123;
514                 }
515             "#]],
516             Direction::Up,
517         );
518     }
519
520     #[test]
521     fn test_moves_param() {
522         check(
523             r#"
524 fn test(one: i32, two$0$0: u32) {}
525
526 fn main() {
527     test(123, 456);
528 }
529 "#,
530             expect![[r#"
531                 fn test(two$0: u32, one: i32) {}
532
533                 fn main() {
534                     test(123, 456);
535                 }
536             "#]],
537             Direction::Up,
538         );
539         check(
540             r#"
541 fn f($0$0arg: u8, arg2: u16) {}
542 "#,
543             expect![[r#"
544                 fn f(arg2: u16, $0arg: u8) {}
545             "#]],
546             Direction::Down,
547         );
548     }
549
550     #[test]
551     fn test_moves_arg_up() {
552         check(
553             r#"
554 fn test(one: i32, two: u32) {}
555
556 fn main() {
557     test(123, 456$0$0);
558 }
559 "#,
560             expect![[r#"
561                 fn test(one: i32, two: u32) {}
562
563                 fn main() {
564                     test(456$0, 123);
565                 }
566             "#]],
567             Direction::Up,
568         );
569     }
570
571     #[test]
572     fn test_moves_arg_down() {
573         check(
574             r#"
575 fn test(one: i32, two: u32) {}
576
577 fn main() {
578     test(123$0$0, 456);
579 }
580 "#,
581             expect![[r#"
582                 fn test(one: i32, two: u32) {}
583
584                 fn main() {
585                     test(456, 123$0);
586                 }
587             "#]],
588             Direction::Down,
589         );
590     }
591
592     #[test]
593     fn test_nowhere_to_move_arg() {
594         check(
595             r#"
596 fn test(one: i32, two: u32) {}
597
598 fn main() {
599     test(123$0$0, 456);
600 }
601 "#,
602             expect![[r#"
603                 fn test(one: i32, two: u32) {}
604
605                 fn main() {
606                     test(123, 456);
607                 }
608             "#]],
609             Direction::Up,
610         );
611     }
612
613     #[test]
614     fn test_moves_generic_param_up() {
615         check(
616             r#"
617 struct Test<A, B$0$0>(A, B);
618
619 fn main() {}
620 "#,
621             expect![[r#"
622                 struct Test<B$0, A>(A, B);
623
624                 fn main() {}
625             "#]],
626             Direction::Up,
627         );
628     }
629
630     #[test]
631     fn test_moves_generic_arg_up() {
632         check(
633             r#"
634 struct Test<A, B>(A, B);
635
636 fn main() {
637     let t = Test::<i32, &str$0$0>(123, "yay");
638 }
639 "#,
640             expect![[r#"
641                 struct Test<A, B>(A, B);
642
643                 fn main() {
644                     let t = Test::<&str$0, i32>(123, "yay");
645                 }
646             "#]],
647             Direction::Up,
648         );
649     }
650
651     #[test]
652     fn test_moves_variant_up() {
653         check(
654             r#"
655 enum Hello {
656     One,
657     Two$0$0
658 }
659
660 fn main() {}
661 "#,
662             expect![[r#"
663                 enum Hello {
664                     Two$0,
665                     One
666                 }
667
668                 fn main() {}
669             "#]],
670             Direction::Up,
671         );
672     }
673
674     #[test]
675     fn test_moves_type_bound_up() {
676         check(
677             r#"
678 trait One {}
679
680 trait Two {}
681
682 fn test<T: One + Two$0$0>(t: T) {}
683
684 fn main() {}
685 "#,
686             expect![[r#"
687                 trait One {}
688
689                 trait Two {}
690
691                 fn test<T: Two$0 + One>(t: T) {}
692
693                 fn main() {}
694             "#]],
695             Direction::Up,
696         );
697     }
698
699     #[test]
700     fn test_prioritizes_trait_items() {
701         check(
702             r#"
703 struct Test;
704
705 trait Yay {
706     type One;
707
708     type Two;
709
710     fn inner();
711 }
712
713 impl Yay for Test {
714     type One = i32;
715
716     type Two = u32;
717
718     fn inner() {$0$0
719         println!("Mmmm");
720     }
721 }
722 "#,
723             expect![[r#"
724                 struct Test;
725
726                 trait Yay {
727                     type One;
728
729                     type Two;
730
731                     fn inner();
732                 }
733
734                 impl Yay for Test {
735                     type One = i32;
736
737                     fn inner() {$0
738                         println!("Mmmm");
739                     }
740
741                     type Two = u32;
742                 }
743             "#]],
744             Direction::Up,
745         );
746     }
747
748     #[test]
749     fn test_weird_nesting() {
750         check(
751             r#"
752 fn test() {
753     mod hello {
754         fn inner() {}
755     }
756
757     mod hi {$0$0
758         fn inner() {}
759     }
760 }
761 "#,
762             expect![[r#"
763                 fn test() {
764                     mod hi {$0
765                         fn inner() {}
766                     }
767
768                     mod hello {
769                         fn inner() {}
770                     }
771                 }
772             "#]],
773             Direction::Up,
774         );
775     }
776
777     #[test]
778     fn test_cursor_at_item_start() {
779         check(
780             r#"
781 $0$0#[derive(Debug)]
782 enum FooBar {
783     Foo,
784     Bar,
785 }
786
787 fn main() {}
788 "#,
789             expect![[r##"
790                 fn main() {}
791
792                 $0#[derive(Debug)]
793                 enum FooBar {
794                     Foo,
795                     Bar,
796                 }
797             "##]],
798             Direction::Down,
799         );
800         check(
801             r#"
802 $0$0enum FooBar {
803     Foo,
804     Bar,
805 }
806
807 fn main() {}
808 "#,
809             expect![[r#"
810                 fn main() {}
811
812                 $0enum FooBar {
813                     Foo,
814                     Bar,
815                 }
816             "#]],
817             Direction::Down,
818         );
819         check(
820             r#"
821 struct Test;
822
823 trait SomeTrait {}
824
825 $0$0impl SomeTrait for Test {}
826
827 fn main() {}
828 "#,
829             expect![[r#"
830                 struct Test;
831
832                 $0impl SomeTrait for Test {}
833
834                 trait SomeTrait {}
835
836                 fn main() {}
837             "#]],
838             Direction::Up,
839         );
840     }
841
842     #[test]
843     fn test_cursor_at_item_end() {
844         check(
845             r#"
846 enum FooBar {
847     Foo,
848     Bar,
849 }$0$0
850
851 fn main() {}
852 "#,
853             expect![[r#"
854                 fn main() {}
855
856                 enum FooBar {
857                     Foo,
858                     Bar,
859                 }$0
860             "#]],
861             Direction::Down,
862         );
863         check(
864             r#"
865 struct Test;
866
867 trait SomeTrait {}
868
869 impl SomeTrait for Test {}$0$0
870
871 fn main() {}
872 "#,
873             expect![[r#"
874                 struct Test;
875
876                 impl SomeTrait for Test {}$0
877
878                 trait SomeTrait {}
879
880                 fn main() {}
881             "#]],
882             Direction::Up,
883         );
884     }
885
886     #[test]
887     fn handles_empty_file() {
888         check(r#"$0$0"#, expect![[r#""#]], Direction::Up);
889     }
890 }