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