Fork of daniellemaywood.uk/gleam — Wasm codegen work
46 kB
2606 lines
1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2025 The Gleam contributors
3
4use std::collections::HashMap;
5
6use lsp_types::{
7 Position, PrepareRenameParams, PrepareRenamePlaceholder, Range, RenameParams,
8 TextDocumentPositionParams, Uri as Url, WorkDoneProgressParams,
9};
10
11use super::{TestProject, find_position_of, hover};
12
13/// Returns the rename range and edit to apply if the rename is valid and can be
14/// carried out.
15/// However if the rename produces an error response from the language server,
16/// the error message is returned.
17fn rename(
18 tester: &TestProject<'_>,
19 new_name: &str,
20 position: Position,
21) -> Result<Option<(Range, lsp_types::WorkspaceEdit)>, String> {
22 let prepare_rename_response = tester.at(position, |engine, params, _| {
23 let params = PrepareRenameParams {
24 text_document_position_params: TextDocumentPositionParams {
25 text_document: params.text_document,
26 position,
27 },
28 work_done_progress_params: WorkDoneProgressParams {
29 work_done_token: None,
30 },
31 };
32 engine.prepare_rename(params).result.unwrap()
33 });
34
35 let range = match prepare_rename_response {
36 Some(lsp_types::PrepareRenameResult::Range(range)) => range,
37 Some(lsp_types::PrepareRenameResult::PrepareRenamePlaceholder(
38 PrepareRenamePlaceholder { range, .. },
39 )) => range,
40 _ => return Ok(None),
41 };
42
43 let outcome = tester.at(position, |engine, params, _| {
44 let params = RenameParams {
45 text_document_position_params: TextDocumentPositionParams {
46 text_document: params.text_document,
47 position,
48 },
49 new_name: new_name.to_string(),
50 work_done_progress_params: WorkDoneProgressParams::default(),
51 };
52 engine.rename(params).result.unwrap()
53 });
54
55 match outcome {
56 Ok(Some(edit)) => Ok(Some((range, edit))),
57 Ok(None) => Ok(None),
58 Err(error) => Err(error.message),
59 }
60}
61
62fn apply_rename(
63 tester: &TestProject<'_>,
64 new_name: &str,
65 position: Position,
66) -> (Range, HashMap<String, String>) {
67 let (range, edit) = rename(tester, new_name, position)
68 .expect("Rename failed")
69 .expect("No rename produced");
70 let changes = edit.changes.expect("No text edit found");
71 (range, apply_code_edit(tester, changes))
72}
73
74fn apply_code_edit(
75 tester: &TestProject<'_>,
76 changes: HashMap<Url, Vec<lsp_types::TextEdit>>,
77) -> HashMap<String, String> {
78 let mut modules = HashMap::new();
79 for (uri, change) in changes {
80 let module_name = tester.module_name_from_url(&uri).expect("Valid uri");
81 let module_code = tester.src_from_module_url(&uri).expect("Module exists");
82
83 _ = modules.insert(module_name, super::apply_code_edit(module_code, change));
84 }
85
86 modules
87}
88
89macro_rules! assert_rename {
90 ($code:literal, $new_name:literal, $position:expr $(,)?) => {
91 assert_rename!(TestProject::for_source($code), $new_name, $position);
92 };
93
94 (($module_name:literal, $module_src:literal), $code:literal, $new_name:literal, $position:expr $(,)?) => {
95 assert_rename!(
96 TestProject::for_source($code).add_module($module_name, $module_src),
97 $new_name,
98 $position
99 );
100 };
101
102 ($project:expr, $new_name:literal, $position:expr $(,)?) => {
103 let project = $project;
104 let src = project.src;
105 let position = $position.find_position(src);
106 let (range, result) = apply_rename(&project, $new_name, position);
107
108 let mut output = String::from("----- BEFORE RENAME\n");
109 for (name, src) in project.root_package_modules.iter() {
110 output.push_str(&format!("-- {name}.gleam\n{src}\n\n"));
111 }
112 output.push_str(&format!(
113 "-- app.gleam\n{}\n\n----- AFTER RENAME\n",
114 hover::show_hover(src, range, range.start)
115 ));
116 for (name, src) in project.root_package_modules.iter() {
117 output.push_str(&format!(
118 "-- {name}.gleam\n{}\n\n",
119 result
120 .get(*name)
121 .map(|string| string.as_str())
122 .unwrap_or(*src)
123 ));
124 }
125 output.push_str(&format!(
126 "-- app.gleam\n{}",
127 result
128 .get("app")
129 .map(|string| string.as_str())
130 .unwrap_or(src)
131 ));
132
133 insta::assert_snapshot!(insta::internals::AutoName, output, src);
134 };
135}
136
137macro_rules! assert_no_rename {
138 ($code:literal, $new_name:literal, $position:expr $(,)?) => {
139 let project = TestProject::for_source($code);
140 assert_no_rename!(&project, $new_name, $position);
141 };
142
143 ($project:expr, $new_name:literal, $position:expr $(,)?) => {
144 let src = $project.src;
145 let position = $position.find_position(src);
146 let result = rename($project, $new_name, position);
147 assert_eq!(result, Ok(None));
148 };
149}
150
151macro_rules! assert_rename_error {
152 ($code:literal, $new_name:literal, $position:expr $(,)?) => {
153 let project = TestProject::for_source($code);
154 assert_rename_error!(&project, $new_name, $position);
155 };
156
157 ($project:expr, $new_name:literal, $position:expr $(,)?) => {
158 let src = $project.src;
159 let position = $position.find_position(src);
160 let error = rename($project, $new_name, position).unwrap_err();
161 let snapshot = format!("Error response message:\n\n{error}");
162 insta::assert_snapshot!(insta::internals::AutoName, snapshot, src);
163 };
164}
165
166#[test]
167fn rename_local_variable() {
168 assert_rename!(
169 "
170pub fn main() {
171 let wibble = 10
172 wibble
173}
174",
175 "wobble",
176 find_position_of("wibble").nth_occurrence(2),
177 );
178}
179
180#[test]
181fn rename_shadowed_local_variable() {
182 assert_rename!(
183 "
184pub fn main() {
185 let wibble = 10
186 let wibble = wibble / 2
187 wibble
188}
189",
190 "wobble",
191 find_position_of("wibble /"),
192 );
193}
194
195#[test]
196fn rename_shadowing_local_variable() {
197 assert_rename!(
198 "
199pub fn main() {
200 let wibble = 10
201 let wibble = wibble / 2
202 wibble
203}
204",
205 "wobble",
206 find_position_of("wibble").nth_occurrence(4),
207 );
208}
209
210#[test]
211fn rename_local_variable_record_access() {
212 assert_rename!(
213 "
214type Wibble {
215 Wibble(wibble: Int)
216}
217
218pub fn main() {
219 let wibble = Wibble(wibble: 1)
220 wibble.wibble
221}
222",
223 "wobble",
224 find_position_of("wibble."),
225 );
226}
227#[test]
228fn rename_local_variable_guard_clause() {
229 assert_rename!(
230 "
231pub fn main() {
232 let wibble = True
233 case Nil {
234 Nil if wibble -> todo
235 _ -> panic
236 }
237 wibble || False
238}
239",
240 "wobble",
241 find_position_of("wibble ||"),
242 );
243}
244
245#[test]
246fn rename_local_variable_from_definition() {
247 assert_rename!(
248 "
249pub fn main() {
250 let wibble = 10
251 let wobble = wibble + 1
252 wobble - wibble
253}
254",
255 "some_value",
256 find_position_of("wibble =")
257 );
258}
259
260#[test]
261fn rename_local_variable_from_definition_nested_pattern() {
262 assert_rename!(
263 "
264pub fn main() {
265 let assert Ok([_, wibble, ..]) = Error(12)
266 wibble
267}
268",
269 "second_element",
270 find_position_of("wibble,")
271 );
272}
273
274#[test]
275fn rename_local_variable_assignment_pattern() {
276 assert_rename!(
277 "
278pub fn main() {
279 let assert Error(12 as something) = Error(12)
280 something
281}
282",
283 "the_error",
284 find_position_of("something").nth_occurrence(2)
285 );
286}
287
288#[test]
289fn rename_local_variable_from_definition_assignment_pattern() {
290 assert_rename!(
291 "
292pub fn main() {
293 let assert Error(12 as something) = Error(12)
294 something
295}
296",
297 "the_error",
298 find_position_of("something)")
299 );
300}
301
302#[test]
303fn rename_local_variable_argument() {
304 assert_rename!(
305 "
306pub fn add(first_number: Int, x: Int) -> Int {
307 x + first_number
308}
309",
310 "second_number",
311 find_position_of("x +")
312 );
313}
314
315#[test]
316fn rename_local_variable_argument_from_definition() {
317 assert_rename!(
318 "
319pub fn wibble(wibble: Float) {
320 wibble /. 0.3
321}
322",
323 "wobble",
324 find_position_of("wibble:")
325 );
326}
327
328#[test]
329fn rename_local_variable_label_shorthand() {
330 assert_rename!(
331 "
332type Wibble {
333 Wibble(wibble: Int)
334}
335
336pub fn main() {
337 let Wibble(wibble:) = todo
338 wibble + 1
339}
340",
341 "wobble",
342 find_position_of("wibble +")
343 );
344}
345
346#[test]
347fn rename_local_variable_label_shorthand_from_definition() {
348 assert_rename!(
349 "
350type Wibble {
351 Wibble(wibble: Int)
352}
353
354pub fn main() {
355 let Wibble(wibble:) = todo
356 wibble + 1
357}
358",
359 "wobble",
360 find_position_of("wibble:)")
361 );
362}
363
364#[test]
365fn rename_local_variable_from_label_shorthand() {
366 assert_rename!(
367 "
368type Wibble {
369 Wibble(wibble: Int)
370}
371
372pub fn main() {
373 let wibble = todo
374 Wibble(wibble:)
375}
376",
377 "wobble",
378 find_position_of("wibble:)")
379 );
380}
381
382#[test]
383fn rename_local_variable_in_bit_array_pattern() {
384 assert_rename!(
385 "
386pub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool {
387 let prefix_size = bit_size(prefix)
388
389 case bits {
390 <<pref:bits-size(prefix_size), _:bits>> if pref == prefix -> True
391 _ -> False
392 }
393}
394",
395 "size_of_prefix",
396 find_position_of("prefix_size =")
397 );
398}
399
400#[test]
401fn rename_local_variable_from_bit_array_pattern() {
402 assert_rename!(
403 "
404pub fn starts_with(bits: BitArray, prefix: BitArray) -> Bool {
405 let prefix_size = bit_size(prefix)
406
407 case bits {
408 <<pref:bits-size(prefix_size), _:bits>> if pref == prefix -> True
409 _ -> False
410 }
411}
412",
413 "size_of_prefix",
414 find_position_of("prefix_size)")
415 );
416}
417
418#[test]
419fn no_rename_keyword() {
420 assert_no_rename!(
421 "
422pub fn main() {}
423",
424 "wibble",
425 find_position_of("fn"),
426 );
427}
428
429#[test]
430fn no_rename_invalid_name() {
431 assert_rename_error!(
432 "
433pub fn main() {
434 let wibble = 10
435 wibble
436}
437",
438 "Not_AValid_Name",
439 find_position_of("wibble").nth_occurrence(2)
440 );
441}
442
443#[test]
444fn rename_function_from_definition() {
445 assert_rename!(
446 (
447 "mod",
448 "
449import app
450
451fn wibble() {
452 app.something()
453}
454"
455 ),
456 "
457pub fn something() {
458 something()
459}
460
461fn something_else() {
462 something()
463}
464",
465 "some_function",
466 find_position_of("something")
467 );
468}
469
470#[test]
471fn rename_function_from_reference() {
472 assert_rename!(
473 (
474 "mod",
475 "
476import app
477
478fn wibble() {
479 app.something()
480}
481"
482 ),
483 "
484pub fn something() {
485 something()
486}
487
488fn something_else() {
489 something()
490}
491",
492 "some_function",
493 find_position_of("something").nth_occurrence(2)
494 );
495}
496
497#[test]
498fn rename_function_from_qualified_reference() {
499 assert_rename!(
500 (
501 "mod",
502 "
503pub fn wibble() {
504 wibble()
505}
506"
507 ),
508 "
509import mod
510
511pub fn main() {
512 mod.wibble()
513}
514",
515 "some_function",
516 find_position_of("wibble")
517 );
518}
519
520#[test]
521fn rename_function_from_unqualified_reference() {
522 assert_rename!(
523 (
524 "mod",
525 "
526pub fn wibble() {
527 wibble()
528}
529"
530 ),
531 "
532import mod.{wibble}
533
534pub fn main() {
535 wibble()
536 mod.wibble()
537}
538",
539 "some_function",
540 find_position_of("wibble(")
541 );
542}
543
544#[test]
545fn rename_aliased_function() {
546 assert_rename!(
547 (
548 "mod",
549 "
550import app.{something as something_else}
551
552fn wibble() {
553 something_else()
554}
555"
556 ),
557 "
558pub fn something() {
559 something()
560}
561
562fn something_else() {
563 something()
564}
565",
566 "some_function",
567 find_position_of("something")
568 );
569}
570
571#[test]
572fn rename_function_shadowing_module() {
573 let src = "
574import gleam/list
575
576pub fn list() {
577 []
578}
579
580pub fn main() {
581 list.map(todo, todo)
582}
583 ";
584
585 assert_rename!(
586 TestProject::for_source(src).add_hex_module("gleam/list", "pub fn map(_, _) {}"),
587 "empty_list",
588 find_position_of("list()")
589 );
590}
591
592#[test]
593fn rename_function_shadowed_by_field_access() {
594 assert_rename!(
595 (
596 "mod",
597 "
598import app
599
600type App {
601 App(something: Int)
602}
603
604pub fn main() {
605 let app = App(10)
606 app.something
607}
608"
609 ),
610 "
611pub fn something() {
612 todo
613}
614",
615 "function",
616 find_position_of("something")
617 );
618}
619
620#[test]
621fn no_rename_function_with_invalid_name() {
622 assert_rename_error!(
623 "
624pub fn main() {
625 let wibble = 10
626 wibble
627}
628",
629 "Not_AValid_Name",
630 find_position_of("main")
631 );
632}
633
634#[test]
635fn no_rename_function_from_other_package() {
636 let src = "
637import wibble
638
639pub fn main() {
640 wibble.wobble()
641}
642";
643
644 assert_no_rename!(
645 &TestProject::for_source(src).add_hex_module("wibble", "pub fn wobble() { todo }"),
646 "something",
647 find_position_of("wobble")
648 );
649}
650
651#[test]
652fn rename_constant_from_definition() {
653 assert_rename!(
654 (
655 "mod",
656 "
657import app
658
659fn wibble() {
660 app.something
661}
662"
663 ),
664 "
665pub const something = 10
666
667pub fn main() {
668 something + { 4 * something }
669}
670",
671 "ten",
672 find_position_of("something")
673 );
674}
675
676#[test]
677fn rename_constant_from_reference() {
678 assert_rename!(
679 (
680 "mod",
681 "
682import app
683
684fn wibble() {
685 app.something
686}
687"
688 ),
689 "
690pub const something = 10
691
692pub fn main() {
693 something + { 4 * something }
694}
695",
696 "ten",
697 find_position_of("something").nth_occurrence(2)
698 );
699}
700
701#[test]
702fn rename_constant_from_qualified_reference() {
703 assert_rename!(
704 (
705 "mod",
706 "
707pub const something = 10
708
709fn wibble() {
710 something
711}
712"
713 ),
714 "
715import mod
716
717pub fn main() {
718 mod.something
719}
720",
721 "ten",
722 find_position_of("something")
723 );
724}
725
726#[test]
727fn rename_constant_from_unqualified_reference() {
728 assert_rename!(
729 (
730 "mod",
731 "
732pub const something = 10
733
734fn wibble() {
735 something
736}
737"
738 ),
739 "
740import mod.{something}
741
742pub fn main() {
743 something + mod.something
744}
745",
746 "ten",
747 find_position_of("something +")
748 );
749}
750
751#[test]
752fn rename_aliased_constant() {
753 assert_rename!(
754 (
755 "mod",
756 "
757import app.{something as some_constant}
758
759fn wibble() {
760 some_constant
761}
762"
763 ),
764 "
765pub const something = 10
766
767pub fn main() {
768 something + { 4 * something }
769}
770",
771 "ten",
772 find_position_of("something")
773 );
774}
775
776#[test]
777fn rename_constant_shadowing_module() {
778 let src = "
779import gleam/list
780
781const list = []
782
783pub fn main() {
784 list.map(todo, todo)
785}
786 ";
787
788 assert_rename!(
789 TestProject::for_source(src).add_hex_module("gleam/list", "pub fn map(_, _) {}"),
790 "empty_list",
791 find_position_of("list =")
792 );
793}
794
795#[test]
796fn rename_constant_shadowed_by_field_access() {
797 assert_rename!(
798 (
799 "mod",
800 "
801import app
802
803type App {
804 App(something: Int)
805}
806
807pub fn main() {
808 let app = App(10)
809 app.something
810}
811"
812 ),
813 "
814pub const something = 10
815",
816 "constant",
817 find_position_of("something")
818 );
819}
820
821#[test]
822fn no_rename_constant_with_invalid_name() {
823 assert_rename_error!(
824 "
825const value = 10
826",
827 "Ten",
828 find_position_of("value")
829 );
830}
831
832#[test]
833fn no_rename_constant_from_other_package() {
834 let src = "
835import wibble
836
837pub fn main() {
838 wibble.wobble
839}
840";
841
842 assert_no_rename!(
843 &TestProject::for_source(src).add_hex_module("wibble", "pub const wobble = 2"),
844 "something",
845 find_position_of("wobble")
846 );
847}
848
849#[test]
850fn rename_type_variant_from_definition() {
851 assert_rename!(
852 (
853 "mod",
854 "
855import app
856
857fn wibble() {
858 app.Constructor(4)
859}
860"
861 ),
862 "
863pub type Wibble {
864 Constructor(Int)
865}
866
867pub fn main() {
868 Constructor(10)
869}
870",
871 "Wibble",
872 find_position_of("Constructor(Int")
873 );
874}
875
876#[test]
877fn rename_type_variant_from_reference() {
878 assert_rename!(
879 (
880 "mod",
881 "
882import app
883
884fn wibble() {
885 app.Constructor(4)
886}
887"
888 ),
889 "
890pub type Wibble {
891 Constructor(Int)
892}
893
894pub fn main() {
895 Constructor(10)
896}
897",
898 "Wibble",
899 find_position_of("Constructor(10")
900 );
901}
902
903#[test]
904fn rename_type_variant_from_qualified_reference() {
905 assert_rename!(
906 (
907 "mod",
908 "
909pub type Wibble {
910 Constructor(Int)
911}
912
913fn wibble() {
914 Constructor(42)
915}
916"
917 ),
918 "
919import mod
920
921pub fn main() {
922 mod.Constructor
923}
924",
925 "Variant",
926 find_position_of("Constructor")
927 );
928}
929
930#[test]
931fn rename_type_variant_from_unqualified_reference() {
932 assert_rename!(
933 (
934 "mod",
935 "
936pub type Wibble {
937 Constructor(Int)
938}
939
940fn wibble() {
941 Constructor(81)
942}
943"
944 ),
945 "
946import mod.{Constructor}
947
948pub fn main() {
949 #(Constructor(75), mod.Constructor(57))
950}
951",
952 "Number",
953 find_position_of("Constructor(75")
954 );
955}
956
957#[test]
958fn rename_aliased_type_variant() {
959 assert_rename!(
960 (
961 "mod",
962 "
963import app.{Constructor as ValueConstructor}
964
965fn wibble() {
966 ValueConstructor(172)
967}
968"
969 ),
970 "
971pub type Wibble {
972 Constructor(Int)
973}
974
975pub fn main() {
976 Constructor(42)
977}
978",
979 "MakeAWibble",
980 find_position_of("Constructor")
981 );
982}
983
984#[test]
985fn no_rename_type_variant_with_invalid_name() {
986 assert_rename_error!(
987 "
988pub type Wibble {
989 Constructor(Int)
990}
991",
992 "name_in_snake_case",
993 find_position_of("Constructor")
994 );
995}
996
997#[test]
998fn rename_custom_type_variant_pattern() {
999 assert_rename!(
1000 "
1001pub type Type {
1002 X
1003 Y
1004}
1005
1006pub fn main(t) {
1007 case t {
1008 X -> 0
1009 Y -> 0
1010 }
1011}
1012",
1013 "Renamed",
1014 find_position_of("X")
1015 );
1016}
1017
1018#[test]
1019fn rename_imported_custom_type_variant_pattern() {
1020 assert_rename!(
1021 (
1022 "other",
1023 "
1024import app
1025
1026pub fn main(t) {
1027 case t {
1028 app.X -> 0
1029 app.Y -> 0
1030 }
1031}
1032"
1033 ),
1034 "
1035pub type Type {
1036 X
1037 Y
1038}
1039",
1040 "Renamed",
1041 find_position_of("X")
1042 );
1043}
1044
1045#[test]
1046fn rename_imported_unqualified_custom_type_variant_pattern() {
1047 assert_rename!(
1048 (
1049 "other",
1050 "
1051import app.{X, Y}
1052
1053pub fn main(t) {
1054 case t {
1055 X -> 0
1056 Y -> 0
1057 }
1058}
1059"
1060 ),
1061 "
1062pub type Type {
1063 X
1064 Y
1065}
1066",
1067 "Renamed",
1068 find_position_of("X")
1069 );
1070}
1071
1072#[test]
1073fn rename_type_variant_pattern_with_arguments() {
1074 assert_rename!(
1075 "
1076pub type Wibble {
1077 Wibble(Int)
1078 Wobble(Float)
1079}
1080
1081fn wibble() {
1082 case Wibble(10) {
1083 Wibble(20) -> todo
1084 Wibble(_) -> panic
1085 }
1086}
1087",
1088 "Variant",
1089 find_position_of("Wibble(10)")
1090 );
1091}
1092
1093#[test]
1094fn rename_type_variant_from_pattern() {
1095 assert_rename!(
1096 "
1097pub type Type {
1098 X
1099 Y
1100}
1101
1102pub fn main(t) {
1103 case t {
1104 X -> 0
1105 Y -> 0
1106 }
1107}
1108",
1109 "Renamed",
1110 find_position_of("X ->")
1111 );
1112}
1113
1114#[test]
1115fn no_rename_type_variant_from_other_package() {
1116 let src = "
1117import wibble
1118
1119pub fn main() {
1120 wibble.Wibble(10)
1121}
1122";
1123
1124 assert_no_rename!(
1125 &TestProject::for_source(src).add_hex_module("wibble", "pub type Wibble { Wibble(Int) }"),
1126 "Constructor",
1127 find_position_of("Wibble")
1128 );
1129}
1130
1131#[test]
1132fn rename_value_in_nested_module() {
1133 assert_rename!(
1134 (
1135 "sub/mod",
1136 "
1137pub fn wibble() {
1138 wibble()
1139}
1140"
1141 ),
1142 "
1143import sub/mod
1144
1145pub fn main() {
1146 mod.wibble()
1147}
1148",
1149 "some_function",
1150 find_position_of("wibble")
1151 );
1152}
1153
1154#[test]
1155fn rename_value_in_aliased_module() {
1156 assert_rename!(
1157 (
1158 "mod",
1159 "
1160pub fn wibble() {
1161 wibble()
1162}
1163"
1164 ),
1165 "
1166import mod as the_module
1167
1168pub fn main() {
1169 the_module.wibble()
1170}
1171",
1172 "some_function",
1173 find_position_of("wibble")
1174 );
1175}
1176
1177#[test]
1178fn rename_aliased_value() {
1179 assert_rename!(
1180 (
1181 "mod",
1182 "
1183import app.{Wibble as Wobble}
1184
1185fn wobble() {
1186 Wobble
1187}
1188"
1189 ),
1190 "
1191pub type Wibble { Wibble }
1192
1193pub fn main() {
1194 Wibble
1195}
1196",
1197 "Wubble",
1198 find_position_of("Wibble }")
1199 );
1200}
1201
1202#[test]
1203fn rename_type_from_definition() {
1204 assert_rename!(
1205 (
1206 "mod",
1207 "
1208import app
1209
1210fn wibble() -> app.Wibble { todo }
1211"
1212 ),
1213 "
1214pub type Wibble { Constructor }
1215
1216pub fn main(w: Wibble) -> Wibble { todo }
1217",
1218 "SomeType",
1219 find_position_of("Wibble")
1220 );
1221}
1222
1223#[test]
1224fn rename_type_from_reference() {
1225 assert_rename!(
1226 (
1227 "mod",
1228 "
1229import app
1230
1231fn wibble() -> app.Wibble { todo }
1232"
1233 ),
1234 "
1235pub type Wibble { Constructor }
1236
1237pub fn main(w: Wibble) -> Wibble { todo }
1238",
1239 "SomeType",
1240 find_position_of("Wibble").nth_occurrence(2)
1241 );
1242}
1243
1244#[test]
1245fn rename_type_from_qualified_reference() {
1246 assert_rename!(
1247 (
1248 "mod",
1249 "
1250pub type Wibble { Constructor }
1251
1252fn wibble(w: Wibble) -> Wibble { todo }
1253"
1254 ),
1255 "
1256import mod
1257
1258pub fn main(w: mod.Wibble) -> mod.Wibble { todo }
1259",
1260 "SomeType",
1261 find_position_of("Wibble")
1262 );
1263}
1264
1265#[test]
1266fn rename_type_from_unqualified_reference() {
1267 assert_rename!(
1268 (
1269 "mod",
1270 "
1271pub type Wibble { Constructor }
1272
1273fn wibble(w: Wibble) -> Wibble { todo }
1274"
1275 ),
1276 "
1277import mod.{type Wibble}
1278
1279pub fn main(w: Wibble) -> mod.Wibble { todo }
1280",
1281 "SomeType",
1282 find_position_of("Wibble)")
1283 );
1284}
1285
1286#[test]
1287fn rename_aliased_type() {
1288 assert_rename!(
1289 (
1290 "mod",
1291 "
1292import app.{type Wibble as Wobble}
1293
1294fn wibble() -> Wobble { todo }
1295"
1296 ),
1297 "
1298pub type Wibble { Constructor }
1299
1300pub fn main(w: Wibble) -> Wibble { todo }
1301",
1302 "SomeType",
1303 find_position_of("Wibble")
1304 );
1305}
1306
1307#[test]
1308fn no_rename_type_with_invalid_name() {
1309 assert_rename_error!(
1310 "
1311type Wibble { Wobble }
1312",
1313 "a_type_name",
1314 find_position_of("Wibble")
1315 );
1316}
1317
1318#[test]
1319fn no_rename_type_from_other_package() {
1320 let src = "
1321import wibble
1322
1323pub fn main() -> wibble.Wibble { todo }
1324";
1325
1326 assert_no_rename!(
1327 &TestProject::for_source(src).add_hex_module("wibble", "pub type Wibble { Wibble }"),
1328 "SomeType",
1329 find_position_of("Wibble")
1330 );
1331}
1332
1333// https://github.com/gleam-lang/gleam/issues/4372
1334#[test]
1335fn rename_type_referenced_in_variant_constructor_argument() {
1336 assert_rename!(
1337 (
1338 "mod",
1339 "
1340import app
1341
1342pub type Wobble {
1343 Wobble(w: app.Wibble)
1344}
1345"
1346 ),
1347 "
1348pub type Wibble {
1349 Wibble
1350}
1351
1352pub fn main() {
1353 let wibble = Wibble
1354}
1355",
1356 "SomeType",
1357 find_position_of("Wibble")
1358 );
1359}
1360
1361// https://github.com/gleam-lang/gleam/issues/4372
1362#[test]
1363fn rename_type_from_variant_constructor_argument() {
1364 assert_rename!(
1365 (
1366 "mod",
1367 "
1368pub type Wibble {
1369 Wibble
1370}
1371
1372pub fn main() {
1373 let wibble = Wibble
1374}
1375"
1376 ),
1377 "
1378import mod
1379
1380pub type Wobble {
1381 Wobble(w: mod.Wibble)
1382}
1383",
1384 "SomeType",
1385 find_position_of("Wibble")
1386 );
1387}
1388
1389// https://github.com/gleam-lang/gleam/issues/4553
1390#[test]
1391fn rename_local_variable_with_label_shorthand() {
1392 assert_rename!(
1393 "
1394pub type Wibble {
1395 Wibble(first: Int, second: Int)
1396}
1397
1398pub fn main() {
1399 let second = 2
1400 Wibble(first: 1, second:)
1401}
1402",
1403 "something",
1404 find_position_of("second =")
1405 );
1406}
1407
1408// https://github.com/gleam-lang/gleam/issues/4748
1409#[test]
1410fn rename_alternative_pattern() {
1411 assert_rename!(
1412 "
1413pub fn main(x) {
1414 case x {
1415 #(wibble, [wobble]) | #(wobble, [wibble, _]) | #(_, [wibble, wobble, ..]) ->
1416 wibble + wobble
1417 _ -> 0
1418 }
1419}
1420",
1421 "new_name",
1422 find_position_of("wibble")
1423 );
1424}
1425
1426// https://github.com/gleam-lang/gleam/issues/5091
1427#[test]
1428fn rename_alternative_pattern_aliases() {
1429 assert_rename!(
1430 "
1431pub fn main(x) {
1432 case x {
1433 [] as list | [_] as list -> list
1434 _ -> []
1435 }
1436}
1437",
1438 "new_name",
1439 find_position_of("list")
1440 );
1441}
1442
1443#[test]
1444fn rename_alternative_pattern_aliases_from_alternative() {
1445 assert_rename!(
1446 "
1447pub fn main(x) {
1448 case x {
1449 [] as list | [_] as list -> list
1450 _ -> []
1451 }
1452}
1453",
1454 "new_name",
1455 find_position_of("list").nth_occurrence(2)
1456 );
1457}
1458
1459#[test]
1460fn rename_alternative_pattern_aliases_from_usage() {
1461 assert_rename!(
1462 "
1463pub fn main(x) {
1464 case x {
1465 [] as list | [_] as list -> list
1466 _ -> []
1467 }
1468}
1469",
1470 "new_name",
1471 find_position_of("list").nth_occurrence(3)
1472 );
1473}
1474
1475#[test]
1476fn rename_alternative_pattern_alias_and_variable_1() {
1477 assert_rename!(
1478 "
1479pub fn main(x) {
1480 case x {
1481 [] as list | [_, ..list] -> list
1482 _ -> []
1483 }
1484}
1485",
1486 "new_name",
1487 find_position_of("list").nth_occurrence(1)
1488 );
1489}
1490
1491#[test]
1492fn rename_alternative_pattern_alias_and_variable_2() {
1493 assert_rename!(
1494 "
1495pub fn main(x) {
1496 case x {
1497 [] as list | [_, ..list] -> list
1498 _ -> []
1499 }
1500}
1501",
1502 "new_name",
1503 find_position_of("list").nth_occurrence(2)
1504 );
1505}
1506
1507#[test]
1508fn rename_alternative_pattern_alias_and_variable_3() {
1509 assert_rename!(
1510 "
1511pub fn main(x) {
1512 case x {
1513 [_, ..list] | [] as list -> list
1514 _ -> []
1515 }
1516}
1517",
1518 "new_name",
1519 find_position_of("list").nth_occurrence(1)
1520 );
1521}
1522
1523#[test]
1524fn rename_alternative_pattern_alias_and_variable_4() {
1525 assert_rename!(
1526 "
1527pub fn main(x) {
1528 case x {
1529 [_, ..list] | [] as list -> list
1530 _ -> []
1531 }
1532}
1533",
1534 "new_name",
1535 find_position_of("list").nth_occurrence(2)
1536 );
1537}
1538
1539#[test]
1540fn rename_alternative_pattern_from_usage() {
1541 assert_rename!(
1542 "
1543pub fn main(x) {
1544 case x {
1545 #(wibble, [wobble]) | #(wobble, [wibble, _]) | #(_, [wibble, wobble, ..]) ->
1546 wibble + wobble
1547 _ -> 0
1548 }
1549}
1550",
1551 "new_name",
1552 find_position_of("wibble +")
1553 );
1554}
1555
1556// https://github.com/gleam-lang/gleam/issues/4605
1557#[test]
1558fn rename_prelude_value() {
1559 assert_rename!(
1560 "
1561pub fn main() {
1562 Ok(10)
1563}
1564",
1565 "Success",
1566 find_position_of("Ok")
1567 );
1568}
1569#[test]
1570fn rename_prelude_type() {
1571 assert_rename!(
1572 "
1573pub fn main() -> Result(Int, Nil) {
1574 Ok(10)
1575}
1576",
1577 "SuccessOrFailure",
1578 find_position_of("Result")
1579 );
1580}
1581
1582#[test]
1583fn rename_variable_with_alternative_pattern_with_same_name() {
1584 assert_rename!(
1585 "
1586pub fn main(x) {
1587 let some_var = 10
1588
1589 case x {
1590 #(some_var, []) | #(_, [some_var]) ->
1591 some_var
1592 _ -> 0
1593 }
1594
1595 some_var
1596}
1597",
1598 "new_name",
1599 find_position_of("some_var")
1600 );
1601}
1602
1603#[test]
1604fn rename_prelude_value_with_prelude_already_imported() {
1605 assert_rename!(
1606 "
1607import gleam
1608
1609pub fn main() {
1610 Ok(gleam.Error(10))
1611}
1612",
1613 "Success",
1614 find_position_of("Ok")
1615 );
1616}
1617
1618#[test]
1619fn rename_prelude_value_with_prelude_import_with_empty_braces() {
1620 assert_rename!(
1621 "
1622import gleam.{}
1623
1624pub fn main() {
1625 Ok(gleam.Error(10))
1626}
1627",
1628 "Success",
1629 find_position_of("Ok")
1630 );
1631}
1632
1633#[test]
1634fn rename_prelude_value_with_other_prelude_value_imported() {
1635 assert_rename!(
1636 "
1637import gleam.{Error}
1638
1639pub fn main() {
1640 Ok(Error(10))
1641}
1642",
1643 "Success",
1644 find_position_of("Ok")
1645 );
1646}
1647
1648#[test]
1649fn rename_prelude_type_with_prelude_value_imported_with_trailing_comma() {
1650 assert_rename!(
1651 "
1652import gleam.{Error,}
1653
1654pub fn main() -> Result(Int, Nil) {
1655 Error(10)
1656}
1657",
1658 "OkOrError",
1659 find_position_of("Result")
1660 );
1661}
1662
1663#[test]
1664fn rename_prelude_value_with_other_module_imported() {
1665 assert_rename!(
1666 ("something", "pub type Something"),
1667 "
1668import something
1669
1670pub fn main() {
1671 Ok(10)
1672}
1673",
1674 "Success",
1675 find_position_of("Ok")
1676 );
1677}
1678
1679#[test]
1680fn rename_module_access_in_clause_guard() {
1681 assert_rename!(
1682 (
1683 "wibble",
1684 "
1685import app
1686
1687pub fn main() {
1688 case app.something {
1689 thing if thing == app.something -> True
1690 _ -> False
1691 }
1692}
1693"
1694 ),
1695 "
1696pub const something = 10
1697",
1698 "new_name",
1699 find_position_of("something")
1700 );
1701}
1702
1703#[test]
1704fn rename_variable_used_in_record_update() {
1705 assert_rename!(
1706 "
1707type Wibble {
1708 Wibble(a: Int, b: Int, c: Int)
1709}
1710
1711fn wibble(wibble: Wibble) {
1712 Wibble(..wibble, c: 1)
1713}
1714",
1715 "value",
1716 find_position_of("wibble:")
1717 );
1718}
1719
1720//https://github.com/gleam-lang/gleam/issues/4941
1721#[test]
1722fn rename_external_function() {
1723 assert_rename!(
1724 r#"
1725pub fn main() { wibble() }
1726
1727@external(erlang, "a", "a")
1728fn wibble() -> Nil
1729"#,
1730 "new_name",
1731 find_position_of("wibble").nth_occurrence(2)
1732 );
1733}
1734
1735#[test]
1736fn rename_external_javascript_function_with_pure_gleam_fallback() {
1737 assert_rename!(
1738 r#"
1739pub fn main() { wibble() }
1740
1741@external(javascript, "a", "a")
1742fn wibble() -> Nil {
1743 Nil
1744}
1745"#,
1746 "new_name",
1747 find_position_of("wibble").nth_occurrence(2)
1748 );
1749}
1750
1751#[test]
1752fn rename_nested_aliased_pattern() {
1753 assert_rename!(
1754 r#"
1755pub fn go(x) {
1756 case x {
1757 [[nested, ..] as wibble, ..] -> todo
1758 _ -> todo
1759 }
1760}
1761 "#,
1762 "new_name",
1763 find_position_of("nested")
1764 );
1765}
1766
1767#[test]
1768fn rename_module_from_import() {
1769 assert_rename!(
1770 TestProject::for_source("import option")
1771 .add_module("option", "pub type Option(a) { Some(a) None }"),
1772 "opt",
1773 find_position_of("option"),
1774 );
1775}
1776
1777#[test]
1778fn rename_works_when_error_is_present() {
1779 assert_rename!(
1780 r#"
1781fn wibble() {
1782 "test string"
1783}
1784
1785pub fn main() {
1786 1 + "1"
1787 echo wibble()
1788}
1789 "#,
1790 "wobble",
1791 find_position_of("wibble")
1792 );
1793}
1794
1795#[test]
1796fn rename_module_from_import_with_alias() {
1797 assert_rename!(
1798 TestProject::for_source("import option as opt")
1799 .add_module("option", "pub type Option(a) { Some(a) None }"),
1800 "o",
1801 find_position_of("opt"),
1802 );
1803}
1804
1805#[test]
1806fn reanem_module_from_import_with_unqualified_values() {
1807 assert_rename!(
1808 TestProject::for_source("import option . { Some, None }")
1809 .add_module("option", "pub type Option(a) { Some(a) None }"),
1810 "opt",
1811 find_position_of("option"),
1812 );
1813}
1814
1815#[test]
1816fn rename_module_from_import_with_unqualified_value_and_alias() {
1817 assert_rename!(
1818 TestProject::for_source("import option . {Some, None} as opt")
1819 .add_module("option", "pub type Option(a) { Some(a) None }"),
1820 "o",
1821 find_position_of("opt"),
1822 );
1823}
1824
1825#[test]
1826fn rename_module_from_import_namespaced() {
1827 assert_rename!(
1828 TestProject::for_source("import std / option ")
1829 .add_module("std/option", "pub type Option(a) { Some(a) None }"),
1830 "opt",
1831 find_position_of("option"),
1832 );
1833}
1834
1835#[test]
1836fn rename_module_from_import_namespaced_with_alias() {
1837 assert_rename!(
1838 TestProject::for_source("import std / option as opt")
1839 .add_module("std/option", "pub type Option(a) { Some(a) None }"),
1840 "o",
1841 find_position_of("opt"),
1842 );
1843}
1844
1845#[test]
1846fn rename_module_from_import_namespaced_with_unqualified_values() {
1847 assert_rename!(
1848 TestProject::for_source("import std / option . { Some, None }")
1849 .add_module("std/option", "pub type Option(a) { Some(a) None }"),
1850 "opt",
1851 find_position_of("option"),
1852 );
1853}
1854
1855#[test]
1856fn rename_module_from_import_namespaced_with_unqualified_value_and_alias() {
1857 assert_rename!(
1858 TestProject::for_source("import std / option . { Some, None } as opt")
1859 .add_module("std/option", "pub type Option(a) { Some(a) None }"),
1860 "o",
1861 find_position_of("opt"),
1862 );
1863}
1864
1865#[test]
1866fn rename_module_from_import_with_alias_to_original_name() {
1867 assert_rename!(
1868 TestProject::for_source("import option as opt")
1869 .add_module("option", "pub type Option(a) { Some(a) None }"),
1870 "option",
1871 find_position_of("opt"),
1872 );
1873}
1874
1875#[test]
1876fn rename_module_from_variant_in_expression() {
1877 let src = r#"
1878import option
1879
1880pub fn main() {
1881 echo option . None
1882}
1883"#;
1884 assert_rename!(
1885 TestProject::for_source(src).add_module("option", "pub type Option(a) { Some(a) None }"),
1886 "opt",
1887 find_position_of("option").nth_occurrence(2)
1888 );
1889}
1890
1891#[test]
1892fn rename_prefix_string_suffix_variable_in_case() {
1893 assert_rename!(
1894 "
1895fn main() -> String {
1896 let wibble = \"1-wibble\"
1897 case wibble {
1898 \"1\" <> rest -> rest
1899 other -> other
1900 }
1901}
1902",
1903 "new_name",
1904 find_position_of("rest").nth_occurrence(1)
1905 );
1906}
1907
1908#[test]
1909fn rename_module_from_constant_in_expression() {
1910 let src = r#"
1911import maths
1912
1913pub fn main() {
1914 echo maths . pi
1915}
1916"#;
1917
1918 assert_rename!(
1919 TestProject::for_source(src).add_module("maths", "pub const pi = 3.14"),
1920 "m",
1921 find_position_of("maths").nth_occurrence(2),
1922 );
1923}
1924
1925#[test]
1926fn rename_module_from_variant_in_const() {
1927 let src = r#"
1928import option
1929
1930const x = option .None
1931"#;
1932
1933 assert_rename!(
1934 TestProject::for_source(src).add_module("option", "pub type Option(a) { Some(a) None }"),
1935 "opt",
1936 find_position_of("option").nth_occurrence(2),
1937 );
1938}
1939
1940#[test]
1941fn rename_module_from_constant_in_const() {
1942 let src = r#"
1943import maths
1944
1945const x = maths . pi
1946"#;
1947
1948 assert_rename!(
1949 TestProject::for_source(src).add_module("maths", "pub const pi = 3.14"),
1950 "m",
1951 find_position_of("maths").nth_occurrence(2),
1952 );
1953}
1954
1955#[test]
1956fn rename_module_from_variant_in_pattern() {
1957 let src = r#"
1958import option
1959
1960pub fn is_some(option) {
1961 case option {
1962 option. Some(_) -> True
1963 option .None -> False
1964 }
1965}
1966"#;
1967
1968 assert_rename!(
1969 TestProject::for_source(src).add_module("option", "pub type Option(a) { Some(a) None }"),
1970 "opt",
1971 find_position_of("option").nth_occurrence(4),
1972 );
1973}
1974
1975#[test]
1976fn rename_prefix_string_suffix_variable_in_case_triggered_from_usage() {
1977 assert_rename!(
1978 "
1979fn main() -> String {
1980 let wibble = \"1-wibble\"
1981 case wibble {
1982 \"1\" <> rest -> rest
1983 other -> other
1984 }
1985}
1986",
1987 "new_name",
1988 find_position_of("rest").nth_occurrence(2)
1989 );
1990}
1991
1992#[test]
1993fn rename_module_from_variant_in_clause_guard() {
1994 let src = r#"
1995import option
1996
1997pub fn count_none(list) {
1998 case list {
1999 [option, ..rest] if option == option . None -> 1 + count_none(rest)
2000 [_, ..rest] -> count_none(rest)
2001 [] -> 0
2002 }
2003}
2004"#;
2005
2006 assert_rename!(
2007 TestProject::for_source(src).add_module("option", "pub type Option(a) { Some(a) None }"),
2008 "opt",
2009 find_position_of("option").nth_occurrence(4),
2010 );
2011}
2012
2013#[test]
2014fn rename_prefix_string_suffix_variable_with_alternative_definition_in_case() {
2015 assert_rename!(
2016 "
2017fn main() -> String {
2018 let wibble = \"1-wibble\"
2019 case wibble {
2020 \"1\" <> rest | \"2\" <> rest -> rest
2021 other -> other
2022 }
2023}
2024",
2025 "new_name",
2026 find_position_of("rest").nth_occurrence(1),
2027 );
2028}
2029
2030#[test]
2031fn rename_module_from_constant_in_clause_guard() {
2032 let src = r#"
2033import maths
2034
2035pub fn count_pi(list) {
2036 case list {
2037 [number, ..rest] if number == maths . pi -> 1 + count_pi(rest)
2038 [_, ..rest] -> count_pi(rest)
2039 [] -> 0
2040 }
2041}
2042"#;
2043
2044 assert_rename!(
2045 TestProject::for_source(src).add_module("maths", "pub const pi = 3.14"),
2046 "m",
2047 find_position_of("maths").nth_occurrence(2),
2048 );
2049}
2050
2051#[test]
2052fn rename_prefix_string_suffix_variable_with_alternative_definition_triggered_from_second_pattern()
2053{
2054 assert_rename!(
2055 "
2056fn main() -> String {
2057 let wibble = \"1-wibble\"
2058 case wibble {
2059 \"1\" <> rest | \"2\" <> rest -> rest
2060 other -> other
2061 }
2062}
2063",
2064 "new_name",
2065 find_position_of("rest").nth_occurrence(2),
2066 );
2067}
2068
2069#[test]
2070fn rename_module_from_type_in_custom_type() {
2071 let src = r#"
2072import option
2073
2074type Value(a) {
2075 Value(option.Option(a))
2076}
2077"#;
2078
2079 assert_rename!(
2080 TestProject::for_source(src).add_module("option", "pub type Option(a) { Some(a) None }"),
2081 "opt",
2082 find_position_of("option").nth_occurrence(2),
2083 );
2084}
2085
2086#[test]
2087fn rename_module_from_type_in_type_alias() {
2088 let src = r#"
2089import option
2090
2091type Option(a) =
2092 option.Option(a)
2093"#;
2094
2095 assert_rename!(
2096 TestProject::for_source(src).add_module("option", "pub type Option(a) { Some(a) None }"),
2097 "opt",
2098 find_position_of("option").nth_occurrence(2),
2099 );
2100}
2101
2102#[test]
2103fn rename_module_from_type_in_annotation() {
2104 let src = r#"
2105import option
2106
2107const x: option.Option(Int) = option.Some(1)
2108"#;
2109
2110 assert_rename!(
2111 TestProject::for_source(src).add_module("option", "pub type Option(a) { Some(a) None }"),
2112 "opt",
2113 find_position_of("option").nth_occurrence(2),
2114 );
2115}
2116
2117#[test]
2118fn rename_module_from_function_call() {
2119 let src = r#"
2120import option
2121
2122pub fn main() {
2123 option.is_some(option.Some(1))
2124}
2125"#;
2126
2127 let option_module = r#"
2128pub type Option(a) {
2129 Some(a)
2130 None
2131}
2132
2133pub fn is_some(option: Option(a)) -> Bool {
2134 case option {
2135 Some(_) -> True
2136 None -> False
2137 }
2138}
2139"#;
2140
2141 assert_rename!(
2142 TestProject::for_source(src).add_module("option", option_module),
2143 "opt",
2144 find_position_of("option").nth_occurrence(2),
2145 );
2146}
2147
2148#[test]
2149fn rename_prefix_string_suffix_variable_in_let_assert() {
2150 assert_rename!(
2151 "
2152fn main() -> String {
2153 let assert \"1\" <> rest = \"1-wibble\"
2154 rest
2155}
2156",
2157 "new_name",
2158 find_position_of("rest").nth_occurrence(1)
2159 );
2160}
2161
2162#[test]
2163fn rename_prefix_string_suffix_variable_in_let_assert_triggered_from_usage() {
2164 assert_rename!(
2165 "
2166fn main() -> String {
2167 let assert \"1\" <> rest = \"1-wibble\"
2168 rest
2169}
2170",
2171 "new_name",
2172 find_position_of("rest").nth_occurrence(2)
2173 );
2174}
2175
2176#[test]
2177fn rename_prefix_string_alias_in_case() {
2178 assert_rename!(
2179 "
2180fn main() -> String {
2181 let wibble = \"1-wibble\"
2182 case wibble {
2183 \"1\" as digit <> rest -> digit <> rest
2184 other -> other
2185 }
2186}
2187",
2188 "new_name",
2189 find_position_of("digit").nth_occurrence(1)
2190 );
2191}
2192
2193#[test]
2194fn rename_prefix_string_alias_in_case_triggered_from_usage() {
2195 assert_rename!(
2196 "
2197fn main() -> String {
2198 let wibble = \"1-wibble\"
2199 case wibble {
2200 \"1\" as digit <> rest -> digit <> rest
2201 other -> other
2202 }
2203}
2204",
2205 "new_name",
2206 find_position_of("digit").nth_occurrence(2)
2207 );
2208}
2209
2210#[test]
2211fn rename_prefix_string_alias_with_alternative_definitions_in_case() {
2212 assert_rename!(
2213 "
2214fn main() -> String {
2215 let wibble = \"1-wibble\"
2216 case wibble {
2217 \"1\" as digit <> rest | \"2\" as digit <> rest -> digit <> rest
2218 other -> other
2219 }
2220}
2221",
2222 "new_name",
2223 find_position_of("digit").nth_occurrence(1)
2224 );
2225}
2226
2227#[test]
2228fn rename_prefix_string_alias_with_alternative_definitions_triggered_from_second_pattern() {
2229 assert_rename!(
2230 "
2231fn main() -> String {
2232 let wibble = \"1-wibble\"
2233 case wibble {
2234 \"1\" as digit <> rest | \"2\" as digit <> rest -> digit <> rest
2235 other -> other
2236 }
2237}
2238",
2239 "new_name",
2240 find_position_of("digit").nth_occurrence(2)
2241 );
2242}
2243
2244#[test]
2245fn rename_prefix_string_alias_in_let_assert() {
2246 assert_rename!(
2247 "
2248fn main() -> String {
2249 let assert \"1\" as digit <> rest = \"1-wibble\"
2250 digit
2251}
2252",
2253 "new_name",
2254 find_position_of("digit").nth_occurrence(1)
2255 );
2256}
2257
2258#[test]
2259fn rename_prefix_string_alias_in_let_assert_triggered_from_usage() {
2260 assert_rename!(
2261 "
2262fn main() -> String {
2263 let assert \"1\" as digit <> rest = \"1-wibble\"
2264 digit
2265}
2266",
2267 "new_name",
2268 find_position_of("digit").nth_occurrence(2)
2269 );
2270}
2271
2272#[test]
2273fn rename_prefix_string_suffix_variable_nested_in_tuple() {
2274 assert_rename!(
2275 "
2276fn main() {
2277 case #(\"1-wibble\", 0) {
2278 #(\"1\" <> rest, _) -> rest
2279 _ -> \"\"
2280 }
2281}
2282",
2283 "new_name",
2284 find_position_of("rest").nth_occurrence(1)
2285 );
2286}
2287
2288#[test]
2289fn rename_prefix_string_alias_used_in_guard() {
2290 assert_rename!(
2291 "
2292fn main() {
2293 case \"1-wibble\" {
2294 \"1\" as digit <> _rest if digit == \"1\" -> digit
2295 _ -> \"\"
2296 }
2297}
2298",
2299 "new_name",
2300 find_position_of("digit").nth_occurrence(1)
2301 );
2302}
2303
2304#[test]
2305fn rename_prefix_string_suffix_used_in_guard() {
2306 assert_rename!(
2307 "
2308fn main() {
2309 case \"1-wibble\" {
2310 \"1\" <> rest if rest == \"-wibble\" -> rest
2311 _ -> \"\"
2312 }
2313}
2314",
2315 "new_name",
2316 find_position_of("rest").nth_occurrence(1)
2317 );
2318}
2319
2320#[test]
2321fn rename_prefix_string_suffix_shadowing_outer_variable() {
2322 assert_rename!(
2323 "
2324fn main() {
2325 let rest = \"outer\"
2326 case \"1-wibble\" {
2327 \"1\" <> rest -> rest
2328 _ -> rest
2329 }
2330}
2331",
2332 "new_name",
2333 find_position_of("rest").nth_occurrence(2)
2334 );
2335}
2336
2337#[test]
2338fn rename_prefix_string_alias_and_suffix_complex_guard() {
2339 assert_rename!(
2340 "
2341fn main() {
2342 case \"1-wibble\" {
2343 \"1\" as digit <> rest if digit == \"1\" && rest == \"-wibble\" -> #(digit, rest)
2344 _ -> #(\"\", \"\")
2345 }
2346}
2347",
2348 "new_name",
2349 find_position_of("digit").nth_occurrence(1)
2350 );
2351}
2352
2353#[test]
2354fn rename_module_from_alias_use() {
2355 let src = r#"
2356import maths as m
2357
2358pub fn main() {
2359 echo m .pi
2360}
2361"#;
2362
2363 assert_rename!(
2364 TestProject::for_source(src).add_module("maths", "pub const pi = 3.14"),
2365 "mth",
2366 find_position_of("m").nth_occurrence(5)
2367 );
2368}
2369
2370#[test]
2371fn rename_local_variable_from_guard() {
2372 assert_rename!(
2373 "
2374pub fn main() {
2375 let wibble = True
2376 let wobble = False
2377 case wibble {
2378 True if wobble -> !wibble
2379 False if !wobble -> wibble
2380 _ -> wobble
2381 }
2382}
2383",
2384 "something_else",
2385 find_position_of("wobble").nth_occurrence(2).under_char('o')
2386 );
2387}
2388
2389#[test]
2390fn alias_imported_module_from_guard() {
2391 assert_rename!(
2392 ("mod", "pub const wibble = 10"),
2393 "
2394import mod
2395
2396pub fn main() {
2397 let wibble = True
2398 case wibble {
2399 True if mod.wibble < 5 -> !wibble
2400 False if mod.wibble != 10 -> wibble
2401 _ -> mod.wibble + 1
2402 }
2403}
2404",
2405 "module",
2406 find_position_of("mod.wibble").under_char('m')
2407 );
2408}
2409
2410#[test]
2411fn rename_module_select_from_guard() {
2412 assert_rename!(
2413 ("mod", "pub const wibble = 10"),
2414 "
2415import mod
2416
2417pub fn main() {
2418 let wibble = True
2419 case wibble {
2420 True if mod.wibble < 5 -> !wibble
2421 False if mod.wibble != 10 -> wibble
2422 _ -> mod.wibble + 1
2423 }
2424}
2425",
2426 "ten",
2427 find_position_of("mod.wibble").under_char('w')
2428 );
2429}
2430
2431#[test]
2432fn rename_type_variable_in_function() {
2433 assert_rename!(
2434 "
2435pub fn first(a: wibble, b: wobble) -> wibble {
2436 a
2437}
2438",
2439 "value",
2440 find_position_of("wibble")
2441 );
2442}
2443
2444#[test]
2445fn rename_type_variable_in_function_from_return() {
2446 assert_rename!(
2447 "
2448pub fn first(a: wibble, b: wobble) -> wibble {
2449 a
2450}
2451",
2452 "value",
2453 find_position_of("-> wibble").under_char('l')
2454 );
2455}
2456
2457#[test]
2458fn rename_type_variable_in_function_body_not_used_in_head() {
2459 assert_rename!(
2460 "
2461pub fn something() {
2462 let x: Result(a, b) = todo
2463 let y: a = case x {
2464 Ok(a) -> a
2465 Error(_) -> panic
2466 }
2467}
2468",
2469 "ok",
2470 find_position_of(": a").under_char('a')
2471 );
2472}
2473
2474#[test]
2475fn rename_type_variable_in_function_used_in_body() {
2476 assert_rename!(
2477 "
2478pub fn first(a: wibble, b: wobble) -> wibble {
2479 let x: wibble = a
2480 let f = fn(a: wibble) -> wibble { a }
2481 f(x)
2482}
2483",
2484 "value",
2485 find_position_of("wibble")
2486 );
2487}
2488
2489#[test]
2490fn rename_type_variable_in_function_from_body() {
2491 assert_rename!(
2492 "
2493pub fn first(a: wibble, b: wobble) -> wibble {
2494 let x: wibble = a
2495 let f = fn(a: wibble) -> wibble { a }
2496 f(x)
2497}
2498",
2499 "value",
2500 find_position_of("x: wibble").under_char('i')
2501 );
2502}
2503
2504#[test]
2505fn type_variable_in_separate_function_is_not_renamed() {
2506 assert_rename!(
2507 "
2508pub fn first(a: wibble, b: wobble) -> wibble {
2509 a
2510}
2511
2512pub fn an_unrelated_function(a: wibble, b: wibble) -> wibble {
2513 a
2514}
2515",
2516 "value",
2517 find_position_of("wibble")
2518 );
2519}
2520
2521#[test]
2522fn rename_type_variable_in_constant() {
2523 assert_rename!(
2524 "
2525pub const empty: List(#(anything, anything)) = []
2526",
2527 "a",
2528 find_position_of("anything")
2529 );
2530}
2531
2532#[test]
2533fn rename_type_variable_in_type_alias() {
2534 assert_rename!(
2535 "
2536pub type Option(a) {
2537 Some(a)
2538 None
2539}
2540
2541pub type Maybe(some_type) =
2542 Option(some_type)
2543",
2544 "something",
2545 find_position_of("Option(some_type").under_char('_')
2546 );
2547}
2548
2549#[test]
2550fn rename_type_variable_in_type_alias_from_head() {
2551 assert_rename!(
2552 "
2553pub type Option(a) {
2554 Some(a)
2555 None
2556}
2557
2558pub type Maybe(some_type) =
2559 Option(some_type)
2560",
2561 "something",
2562 find_position_of("some_type")
2563 );
2564}
2565
2566#[test]
2567fn rename_type_variable_in_custom_type_from_head() {
2568 assert_rename!(
2569 "
2570pub type Option(anything) {
2571 Some(anything)
2572 None
2573}
2574",
2575 "something",
2576 find_position_of("anything")
2577 );
2578}
2579
2580#[test]
2581fn rename_type_variable_in_custom_type_from_constructor() {
2582 assert_rename!(
2583 "
2584pub type Option(anything) {
2585 Some(anything)
2586 None
2587}
2588",
2589 "something",
2590 find_position_of("Some(anything").under_char('i')
2591 );
2592}
2593
2594#[test]
2595fn invalid_type_variable_name() {
2596 assert_rename_error!(
2597 "
2598pub type Option(anything) {
2599 Some(anything)
2600 None
2601}
2602",
2603 "SomeType",
2604 find_position_of("anything")
2605 );
2606}