aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ssr/src/tests.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ssr/src/tests.rs')
-rw-r--r--crates/ra_ssr/src/tests.rs473
1 files changed, 389 insertions, 84 deletions
diff --git a/crates/ra_ssr/src/tests.rs b/crates/ra_ssr/src/tests.rs
index f20ae2cdf..b38807c0f 100644
--- a/crates/ra_ssr/src/tests.rs
+++ b/crates/ra_ssr/src/tests.rs
@@ -1,5 +1,8 @@
1use crate::{MatchFinder, SsrRule}; 1use crate::{MatchFinder, SsrRule};
2use ra_db::{FileId, SourceDatabaseExt}; 2use expect::{expect, Expect};
3use ra_db::{salsa::Durability, FileId, FilePosition, SourceDatabaseExt};
4use rustc_hash::FxHashSet;
5use std::sync::Arc;
3use test_utils::mark; 6use test_utils::mark;
4 7
5fn parse_error_text(query: &str) -> String { 8fn parse_error_text(query: &str) -> String {
@@ -36,7 +39,7 @@ fn parser_repeated_name() {
36fn parser_invalid_pattern() { 39fn parser_invalid_pattern() {
37 assert_eq!( 40 assert_eq!(
38 parse_error_text(" ==>> ()"), 41 parse_error_text(" ==>> ()"),
39 "Parse error: Pattern is not a valid Rust expression, type, item, path or pattern" 42 "Parse error: Not a valid Rust expression, type, item, path or pattern"
40 ); 43 );
41} 44}
42 45
@@ -44,7 +47,7 @@ fn parser_invalid_pattern() {
44fn parser_invalid_template() { 47fn parser_invalid_template() {
45 assert_eq!( 48 assert_eq!(
46 parse_error_text("() ==>> )"), 49 parse_error_text("() ==>> )"),
47 "Parse error: Replacement is not a valid Rust expression, type, item, path or pattern" 50 "Parse error: Not a valid Rust expression, type, item, path or pattern"
48 ); 51 );
49} 52}
50 53
@@ -56,39 +59,44 @@ fn parser_undefined_placeholder_in_replacement() {
56 ); 59 );
57} 60}
58 61
59fn single_file(code: &str) -> (ra_ide_db::RootDatabase, FileId) { 62/// `code` may optionally contain a cursor marker `<|>`. If it doesn't, then the position will be
63/// the start of the file.
64pub(crate) fn single_file(code: &str) -> (ra_ide_db::RootDatabase, FilePosition) {
60 use ra_db::fixture::WithFixture; 65 use ra_db::fixture::WithFixture;
61 ra_ide_db::RootDatabase::with_single_file(code) 66 use ra_ide_db::symbol_index::SymbolsDatabase;
62} 67 let (mut db, position) = if code.contains(test_utils::CURSOR_MARKER) {
63 68 ra_ide_db::RootDatabase::with_position(code)
64fn assert_ssr_transform(rule: &str, input: &str, result: &str) { 69 } else {
65 assert_ssr_transforms(&[rule], input, result); 70 let (db, file_id) = ra_ide_db::RootDatabase::with_single_file(code);
71 (db, FilePosition { file_id, offset: 0.into() })
72 };
73 let mut local_roots = FxHashSet::default();
74 local_roots.insert(ra_db::fixture::WORKSPACE);
75 db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
76 (db, position)
66} 77}
67 78
68fn normalize_code(code: &str) -> String { 79fn assert_ssr_transform(rule: &str, input: &str, expected: Expect) {
69 let (db, file_id) = single_file(code); 80 assert_ssr_transforms(&[rule], input, expected);
70 db.file_text(file_id).to_string()
71} 81}
72 82
73fn assert_ssr_transforms(rules: &[&str], input: &str, result: &str) { 83fn assert_ssr_transforms(rules: &[&str], input: &str, expected: Expect) {
74 let (db, file_id) = single_file(input); 84 let (db, position) = single_file(input);
75 let mut match_finder = MatchFinder::new(&db); 85 let mut match_finder = MatchFinder::in_context(&db, position);
76 for rule in rules { 86 for rule in rules {
77 let rule: SsrRule = rule.parse().unwrap(); 87 let rule: SsrRule = rule.parse().unwrap();
78 match_finder.add_rule(rule); 88 match_finder.add_rule(rule).unwrap();
79 } 89 }
80 if let Some(edits) = match_finder.edits_for_file(file_id) { 90 let edits = match_finder.edits();
81 // Note, db.file_text is not necessarily the same as `input`, since fixture parsing alters 91 if edits.is_empty() {
82 // stuff.
83 let mut after = db.file_text(file_id).to_string();
84 edits.apply(&mut after);
85 // Likewise, we need to make sure that whatever transformations fixture parsing applies,
86 // also get applied to our expected result.
87 let result = normalize_code(result);
88 assert_eq!(after, result);
89 } else {
90 panic!("No edits were made"); 92 panic!("No edits were made");
91 } 93 }
94 assert_eq!(edits[0].file_id, position.file_id);
95 // Note, db.file_text is not necessarily the same as `input`, since fixture parsing alters
96 // stuff.
97 let mut actual = db.file_text(position.file_id).to_string();
98 edits[0].edit.apply(&mut actual);
99 expected.assert_eq(&actual);
92} 100}
93 101
94fn print_match_debug_info(match_finder: &MatchFinder, file_id: FileId, snippet: &str) { 102fn print_match_debug_info(match_finder: &MatchFinder, file_id: FileId, snippet: &str) {
@@ -104,39 +112,34 @@ fn print_match_debug_info(match_finder: &MatchFinder, file_id: FileId, snippet:
104} 112}
105 113
106fn assert_matches(pattern: &str, code: &str, expected: &[&str]) { 114fn assert_matches(pattern: &str, code: &str, expected: &[&str]) {
107 let (db, file_id) = single_file(code); 115 let (db, position) = single_file(code);
108 let mut match_finder = MatchFinder::new(&db); 116 let mut match_finder = MatchFinder::in_context(&db, position);
109 match_finder.add_search_pattern(pattern.parse().unwrap()); 117 match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap();
110 let matched_strings: Vec<String> = match_finder 118 let matched_strings: Vec<String> =
111 .find_matches_in_file(file_id) 119 match_finder.matches().flattened().matches.iter().map(|m| m.matched_text()).collect();
112 .flattened()
113 .matches
114 .iter()
115 .map(|m| m.matched_text())
116 .collect();
117 if matched_strings != expected && !expected.is_empty() { 120 if matched_strings != expected && !expected.is_empty() {
118 print_match_debug_info(&match_finder, file_id, &expected[0]); 121 print_match_debug_info(&match_finder, position.file_id, &expected[0]);
119 } 122 }
120 assert_eq!(matched_strings, expected); 123 assert_eq!(matched_strings, expected);
121} 124}
122 125
123fn assert_no_match(pattern: &str, code: &str) { 126fn assert_no_match(pattern: &str, code: &str) {
124 let (db, file_id) = single_file(code); 127 let (db, position) = single_file(code);
125 let mut match_finder = MatchFinder::new(&db); 128 let mut match_finder = MatchFinder::in_context(&db, position);
126 match_finder.add_search_pattern(pattern.parse().unwrap()); 129 match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap();
127 let matches = match_finder.find_matches_in_file(file_id).flattened().matches; 130 let matches = match_finder.matches().flattened().matches;
128 if !matches.is_empty() { 131 if !matches.is_empty() {
129 print_match_debug_info(&match_finder, file_id, &matches[0].matched_text()); 132 print_match_debug_info(&match_finder, position.file_id, &matches[0].matched_text());
130 panic!("Got {} matches when we expected none: {:#?}", matches.len(), matches); 133 panic!("Got {} matches when we expected none: {:#?}", matches.len(), matches);
131 } 134 }
132} 135}
133 136
134fn assert_match_failure_reason(pattern: &str, code: &str, snippet: &str, expected_reason: &str) { 137fn assert_match_failure_reason(pattern: &str, code: &str, snippet: &str, expected_reason: &str) {
135 let (db, file_id) = single_file(code); 138 let (db, position) = single_file(code);
136 let mut match_finder = MatchFinder::new(&db); 139 let mut match_finder = MatchFinder::in_context(&db, position);
137 match_finder.add_search_pattern(pattern.parse().unwrap()); 140 match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap();
138 let mut reasons = Vec::new(); 141 let mut reasons = Vec::new();
139 for d in match_finder.debug_where_text_equal(file_id, snippet) { 142 for d in match_finder.debug_where_text_equal(position.file_id, snippet) {
140 if let Some(reason) = d.match_failure_reason() { 143 if let Some(reason) = d.match_failure_reason() {
141 reasons.push(reason.to_owned()); 144 reasons.push(reason.to_owned());
142 } 145 }
@@ -149,7 +152,7 @@ fn ssr_function_to_method() {
149 assert_ssr_transform( 152 assert_ssr_transform(
150 "my_function($a, $b) ==>> ($a).my_method($b)", 153 "my_function($a, $b) ==>> ($a).my_method($b)",
151 "fn my_function() {} fn main() { loop { my_function( other_func(x, y), z + w) } }", 154 "fn my_function() {} fn main() { loop { my_function( other_func(x, y), z + w) } }",
152 "fn my_function() {} fn main() { loop { (other_func(x, y)).my_method(z + w) } }", 155 expect![["fn my_function() {} fn main() { loop { (other_func(x, y)).my_method(z + w) } }"]],
153 ) 156 )
154} 157}
155 158
@@ -157,8 +160,19 @@ fn ssr_function_to_method() {
157fn ssr_nested_function() { 160fn ssr_nested_function() {
158 assert_ssr_transform( 161 assert_ssr_transform(
159 "foo($a, $b, $c) ==>> bar($c, baz($a, $b))", 162 "foo($a, $b, $c) ==>> bar($c, baz($a, $b))",
160 "fn foo() {} fn main { foo (x + value.method(b), x+y-z, true && false) }", 163 r#"
161 "fn foo() {} fn main { bar(true && false, baz(x + value.method(b), x+y-z)) }", 164 //- /lib.rs crate:foo
165 fn foo() {}
166 fn bar() {}
167 fn baz() {}
168 fn main { foo (x + value.method(b), x+y-z, true && false) }
169 "#,
170 expect![[r#"
171 fn foo() {}
172 fn bar() {}
173 fn baz() {}
174 fn main { bar(true && false, baz(x + value.method(b), x+y-z)) }
175 "#]],
162 ) 176 )
163} 177}
164 178
@@ -167,7 +181,7 @@ fn ssr_expected_spacing() {
167 assert_ssr_transform( 181 assert_ssr_transform(
168 "foo($x) + bar() ==>> bar($x)", 182 "foo($x) + bar() ==>> bar($x)",
169 "fn foo() {} fn bar() {} fn main() { foo(5) + bar() }", 183 "fn foo() {} fn bar() {} fn main() { foo(5) + bar() }",
170 "fn foo() {} fn bar() {} fn main() { bar(5) }", 184 expect![["fn foo() {} fn bar() {} fn main() { bar(5) }"]],
171 ); 185 );
172} 186}
173 187
@@ -176,7 +190,7 @@ fn ssr_with_extra_space() {
176 assert_ssr_transform( 190 assert_ssr_transform(
177 "foo($x ) + bar() ==>> bar($x)", 191 "foo($x ) + bar() ==>> bar($x)",
178 "fn foo() {} fn bar() {} fn main() { foo( 5 ) +bar( ) }", 192 "fn foo() {} fn bar() {} fn main() { foo( 5 ) +bar( ) }",
179 "fn foo() {} fn bar() {} fn main() { bar(5) }", 193 expect![["fn foo() {} fn bar() {} fn main() { bar(5) }"]],
180 ); 194 );
181} 195}
182 196
@@ -184,8 +198,8 @@ fn ssr_with_extra_space() {
184fn ssr_keeps_nested_comment() { 198fn ssr_keeps_nested_comment() {
185 assert_ssr_transform( 199 assert_ssr_transform(
186 "foo($x) ==>> bar($x)", 200 "foo($x) ==>> bar($x)",
187 "fn foo() {} fn main() { foo(other(5 /* using 5 */)) }", 201 "fn foo() {} fn bar() {} fn main() { foo(other(5 /* using 5 */)) }",
188 "fn foo() {} fn main() { bar(other(5 /* using 5 */)) }", 202 expect![["fn foo() {} fn bar() {} fn main() { bar(other(5 /* using 5 */)) }"]],
189 ) 203 )
190} 204}
191 205
@@ -193,17 +207,25 @@ fn ssr_keeps_nested_comment() {
193fn ssr_keeps_comment() { 207fn ssr_keeps_comment() {
194 assert_ssr_transform( 208 assert_ssr_transform(
195 "foo($x) ==>> bar($x)", 209 "foo($x) ==>> bar($x)",
196 "fn foo() {} fn main() { foo(5 /* using 5 */) }", 210 "fn foo() {} fn bar() {} fn main() { foo(5 /* using 5 */) }",
197 "fn foo() {} fn main() { bar(5)/* using 5 */ }", 211 expect![["fn foo() {} fn bar() {} fn main() { bar(5)/* using 5 */ }"]],
198 ) 212 )
199} 213}
200 214
201#[test] 215#[test]
202fn ssr_struct_lit() { 216fn ssr_struct_lit() {
203 assert_ssr_transform( 217 assert_ssr_transform(
204 "foo{a: $a, b: $b} ==>> foo::new($a, $b)", 218 "Foo{a: $a, b: $b} ==>> Foo::new($a, $b)",
205 "fn foo() {} fn main() { foo{b:2, a:1} }", 219 r#"
206 "fn foo() {} fn main() { foo::new(1, 2) }", 220 struct Foo() {}
221 impl Foo { fn new() {} }
222 fn main() { Foo{b:2, a:1} }
223 "#,
224 expect![[r#"
225 struct Foo() {}
226 impl Foo { fn new() {} }
227 fn main() { Foo::new(1, 2) }
228 "#]],
207 ) 229 )
208} 230}
209 231
@@ -315,7 +337,7 @@ fn match_struct_instantiation() {
315fn match_path() { 337fn match_path() {
316 let code = r#" 338 let code = r#"
317 mod foo { 339 mod foo {
318 fn bar() {} 340 pub fn bar() {}
319 } 341 }
320 fn f() {foo::bar(42)}"#; 342 fn f() {foo::bar(42)}"#;
321 assert_matches("foo::bar", code, &["foo::bar"]); 343 assert_matches("foo::bar", code, &["foo::bar"]);
@@ -328,6 +350,60 @@ fn match_pattern() {
328 assert_matches("Some($a)", "struct Some(); fn f() {if let Some(x) = foo() {}}", &["Some(x)"]); 350 assert_matches("Some($a)", "struct Some(); fn f() {if let Some(x) = foo() {}}", &["Some(x)"]);
329} 351}
330 352
353// If our pattern has a full path, e.g. a::b::c() and the code has c(), but c resolves to
354// a::b::c, then we should match.
355#[test]
356fn match_fully_qualified_fn_path() {
357 let code = r#"
358 mod a {
359 pub mod b {
360 pub fn c(_: i32) {}
361 }
362 }
363 use a::b::c;
364 fn f1() {
365 c(42);
366 }
367 "#;
368 assert_matches("a::b::c($a)", code, &["c(42)"]);
369}
370
371#[test]
372fn match_resolved_type_name() {
373 let code = r#"
374 mod m1 {
375 pub mod m2 {
376 pub trait Foo<T> {}
377 }
378 }
379 mod m3 {
380 trait Foo<T> {}
381 fn f1(f: Option<&dyn Foo<bool>>) {}
382 }
383 mod m4 {
384 use crate::m1::m2::Foo;
385 fn f1(f: Option<&dyn Foo<i32>>) {}
386 }
387 "#;
388 assert_matches("m1::m2::Foo<$t>", code, &["Foo<i32>"]);
389}
390
391#[test]
392fn type_arguments_within_path() {
393 mark::check!(type_arguments_within_path);
394 let code = r#"
395 mod foo {
396 pub struct Bar<T> {t: T}
397 impl<T> Bar<T> {
398 pub fn baz() {}
399 }
400 }
401 fn f1() {foo::Bar::<i32>::baz();}
402 "#;
403 assert_no_match("foo::Bar::<i64>::baz()", code);
404 assert_matches("foo::Bar::<i32>::baz()", code, &["foo::Bar::<i32>::baz()"]);
405}
406
331#[test] 407#[test]
332fn literal_constraint() { 408fn literal_constraint() {
333 mark::check!(literal_constraint); 409 mark::check!(literal_constraint);
@@ -416,8 +492,8 @@ fn no_match_split_expression() {
416fn replace_function_call() { 492fn replace_function_call() {
417 assert_ssr_transform( 493 assert_ssr_transform(
418 "foo() ==>> bar()", 494 "foo() ==>> bar()",
419 "fn foo() {} fn f1() {foo(); foo();}", 495 "fn foo() {} fn bar() {} fn f1() {foo(); foo();}",
420 "fn foo() {} fn f1() {bar(); bar();}", 496 expect![["fn foo() {} fn bar() {} fn f1() {bar(); bar();}"]],
421 ); 497 );
422} 498}
423 499
@@ -425,8 +501,8 @@ fn replace_function_call() {
425fn replace_function_call_with_placeholders() { 501fn replace_function_call_with_placeholders() {
426 assert_ssr_transform( 502 assert_ssr_transform(
427 "foo($a, $b) ==>> bar($b, $a)", 503 "foo($a, $b) ==>> bar($b, $a)",
428 "fn foo() {} fn f1() {foo(5, 42)}", 504 "fn foo() {} fn bar() {} fn f1() {foo(5, 42)}",
429 "fn foo() {} fn f1() {bar(42, 5)}", 505 expect![["fn foo() {} fn bar() {} fn f1() {bar(42, 5)}"]],
430 ); 506 );
431} 507}
432 508
@@ -434,26 +510,120 @@ fn replace_function_call_with_placeholders() {
434fn replace_nested_function_calls() { 510fn replace_nested_function_calls() {
435 assert_ssr_transform( 511 assert_ssr_transform(
436 "foo($a) ==>> bar($a)", 512 "foo($a) ==>> bar($a)",
437 "fn foo() {} fn f1() {foo(foo(42))}", 513 "fn foo() {} fn bar() {} fn f1() {foo(foo(42))}",
438 "fn foo() {} fn f1() {bar(bar(42))}", 514 expect![["fn foo() {} fn bar() {} fn f1() {bar(bar(42))}"]],
439 ); 515 );
440} 516}
441 517
442#[test] 518#[test]
443fn replace_type() { 519fn replace_associated_function_call() {
444 assert_ssr_transform( 520 assert_ssr_transform(
445 "Result<(), $a> ==>> Option<$a>", 521 "Foo::new() ==>> Bar::new()",
446 "struct Result<T, E> {} fn f1() -> Result<(), Vec<Error>> {foo()}", 522 r#"
447 "struct Result<T, E> {} fn f1() -> Option<Vec<Error>> {foo()}", 523 struct Foo {}
524 impl Foo { fn new() {} }
525 struct Bar {}
526 impl Bar { fn new() {} }
527 fn f1() {Foo::new();}
528 "#,
529 expect![[r#"
530 struct Foo {}
531 impl Foo { fn new() {} }
532 struct Bar {}
533 impl Bar { fn new() {} }
534 fn f1() {Bar::new();}
535 "#]],
536 );
537}
538
539#[test]
540fn replace_path_in_different_contexts() {
541 // Note the <|> inside module a::b which marks the point where the rule is interpreted. We
542 // replace foo with bar, but both need different path qualifiers in different contexts. In f4,
543 // foo is unqualified because of a use statement, however the replacement needs to be fully
544 // qualified.
545 assert_ssr_transform(
546 "c::foo() ==>> c::bar()",
547 r#"
548 mod a {
549 pub mod b {<|>
550 pub mod c {
551 pub fn foo() {}
552 pub fn bar() {}
553 fn f1() { foo() }
554 }
555 fn f2() { c::foo() }
556 }
557 fn f3() { b::c::foo() }
558 }
559 use a::b::c::foo;
560 fn f4() { foo() }
561 "#,
562 expect![[r#"
563 mod a {
564 pub mod b {
565 pub mod c {
566 pub fn foo() {}
567 pub fn bar() {}
568 fn f1() { bar() }
569 }
570 fn f2() { c::bar() }
571 }
572 fn f3() { b::c::bar() }
573 }
574 use a::b::c::foo;
575 fn f4() { a::b::c::bar() }
576 "#]],
448 ); 577 );
449} 578}
450 579
451#[test] 580#[test]
452fn replace_struct_init() { 581fn replace_associated_function_with_generics() {
453 assert_ssr_transform( 582 assert_ssr_transform(
454 "Foo {a: $a, b: $b} ==>> Foo::new($a, $b)", 583 "c::Foo::<$a>::new() ==>> d::Bar::<$a>::default()",
455 "struct Foo {} fn f1() {Foo{b: 1, a: 2}}", 584 r#"
456 "struct Foo {} fn f1() {Foo::new(2, 1)}", 585 mod c {
586 pub struct Foo<T> {v: T}
587 impl<T> Foo<T> { pub fn new() {} }
588 fn f1() {
589 Foo::<i32>::new();
590 }
591 }
592 mod d {
593 pub struct Bar<T> {v: T}
594 impl<T> Bar<T> { pub fn default() {} }
595 fn f1() {
596 super::c::Foo::<i32>::new();
597 }
598 }
599 "#,
600 expect![[r#"
601 mod c {
602 pub struct Foo<T> {v: T}
603 impl<T> Foo<T> { pub fn new() {} }
604 fn f1() {
605 crate::d::Bar::<i32>::default();
606 }
607 }
608 mod d {
609 pub struct Bar<T> {v: T}
610 impl<T> Bar<T> { pub fn default() {} }
611 fn f1() {
612 Bar::<i32>::default();
613 }
614 }
615 "#]],
616 );
617}
618
619#[test]
620fn replace_type() {
621 assert_ssr_transform(
622 "Result<(), $a> ==>> Option<$a>",
623 "struct Result<T, E> {} struct Option<T> {} fn f1() -> Result<(), Vec<Error>> {foo()}",
624 expect![[
625 "struct Result<T, E> {} struct Option<T> {} fn f1() -> Option<Vec<Error>> {foo()}"
626 ]],
457 ); 627 );
458} 628}
459 629
@@ -462,12 +632,12 @@ fn replace_macro_invocations() {
462 assert_ssr_transform( 632 assert_ssr_transform(
463 "try!($a) ==>> $a?", 633 "try!($a) ==>> $a?",
464 "macro_rules! try {() => {}} fn f1() -> Result<(), E> {bar(try!(foo()));}", 634 "macro_rules! try {() => {}} fn f1() -> Result<(), E> {bar(try!(foo()));}",
465 "macro_rules! try {() => {}} fn f1() -> Result<(), E> {bar(foo()?);}", 635 expect![["macro_rules! try {() => {}} fn f1() -> Result<(), E> {bar(foo()?);}"]],
466 ); 636 );
467 assert_ssr_transform( 637 assert_ssr_transform(
468 "foo!($a($b)) ==>> foo($b, $a)", 638 "foo!($a($b)) ==>> foo($b, $a)",
469 "macro_rules! foo {() => {}} fn f1() {foo!(abc(def() + 2));}", 639 "macro_rules! foo {() => {}} fn f1() {foo!(abc(def() + 2));}",
470 "macro_rules! foo {() => {}} fn f1() {foo(def() + 2, abc);}", 640 expect![["macro_rules! foo {() => {}} fn f1() {foo(def() + 2, abc);}"]],
471 ); 641 );
472} 642}
473 643
@@ -476,12 +646,12 @@ fn replace_binary_op() {
476 assert_ssr_transform( 646 assert_ssr_transform(
477 "$a + $b ==>> $b + $a", 647 "$a + $b ==>> $b + $a",
478 "fn f() {2 * 3 + 4 * 5}", 648 "fn f() {2 * 3 + 4 * 5}",
479 "fn f() {4 * 5 + 2 * 3}", 649 expect![["fn f() {4 * 5 + 2 * 3}"]],
480 ); 650 );
481 assert_ssr_transform( 651 assert_ssr_transform(
482 "$a + $b ==>> $b + $a", 652 "$a + $b ==>> $b + $a",
483 "fn f() {1 + 2 + 3 + 4}", 653 "fn f() {1 + 2 + 3 + 4}",
484 "fn f() {4 + 3 + 2 + 1}", 654 expect![["fn f() {4 + 3 + 2 + 1}"]],
485 ); 655 );
486} 656}
487 657
@@ -494,8 +664,23 @@ fn match_binary_op() {
494fn multiple_rules() { 664fn multiple_rules() {
495 assert_ssr_transforms( 665 assert_ssr_transforms(
496 &["$a + 1 ==>> add_one($a)", "$a + $b ==>> add($a, $b)"], 666 &["$a + 1 ==>> add_one($a)", "$a + $b ==>> add($a, $b)"],
497 "fn f() -> i32 {3 + 2 + 1}", 667 "fn add() {} fn add_one() {} fn f() -> i32 {3 + 2 + 1}",
498 "fn f() -> i32 {add_one(add(3, 2))}", 668 expect![["fn add() {} fn add_one() {} fn f() -> i32 {add_one(add(3, 2))}"]],
669 )
670}
671
672#[test]
673fn multiple_rules_with_nested_matches() {
674 assert_ssr_transforms(
675 &["foo1($a) ==>> bar1($a)", "foo2($a) ==>> bar2($a)"],
676 r#"
677 fn foo1() {} fn foo2() {} fn bar1() {} fn bar2() {}
678 fn f() {foo1(foo2(foo1(foo2(foo1(42)))))}
679 "#,
680 expect![[r#"
681 fn foo1() {} fn foo2() {} fn bar1() {} fn bar2() {}
682 fn f() {bar1(bar2(bar1(bar2(bar1(42)))))}
683 "#]],
499 ) 684 )
500} 685}
501 686
@@ -527,12 +712,37 @@ fn replace_within_macro_expansion() {
527 macro_rules! macro1 { 712 macro_rules! macro1 {
528 ($a:expr) => {$a} 713 ($a:expr) => {$a}
529 } 714 }
530 fn f() {macro1!(5.x().foo().o2())}"#, 715 fn bar() {}
716 fn f() {macro1!(5.x().foo().o2())}
717 "#,
718 expect![[r#"
719 macro_rules! macro1 {
720 ($a:expr) => {$a}
721 }
722 fn bar() {}
723 fn f() {macro1!(bar(5.x()).o2())}
724 "#]],
725 )
726}
727
728#[test]
729fn replace_outside_and_within_macro_expansion() {
730 assert_ssr_transform(
731 "foo($a) ==>> bar($a)",
531 r#" 732 r#"
733 fn foo() {} fn bar() {}
734 macro_rules! macro1 {
735 ($a:expr) => {$a}
736 }
737 fn f() {foo(foo(macro1!(foo(foo(42)))))}
738 "#,
739 expect![[r#"
740 fn foo() {} fn bar() {}
532 macro_rules! macro1 { 741 macro_rules! macro1 {
533 ($a:expr) => {$a} 742 ($a:expr) => {$a}
534 } 743 }
535 fn f() {macro1!(bar(5.x()).o2())}"#, 744 fn f() {bar(bar(macro1!(bar(bar(42)))))}
745 "#]],
536 ) 746 )
537} 747}
538 748
@@ -544,12 +754,14 @@ fn preserves_whitespace_within_macro_expansion() {
544 macro_rules! macro1 { 754 macro_rules! macro1 {
545 ($a:expr) => {$a} 755 ($a:expr) => {$a}
546 } 756 }
547 fn f() {macro1!(1 * 2 + 3 + 4}"#, 757 fn f() {macro1!(1 * 2 + 3 + 4}
548 r#" 758 "#,
759 expect![[r#"
549 macro_rules! macro1 { 760 macro_rules! macro1 {
550 ($a:expr) => {$a} 761 ($a:expr) => {$a}
551 } 762 }
552 fn f() {macro1!(4 - 3 - 1 * 2}"#, 763 fn f() {macro1!(4 - 3 - 1 * 2}
764 "#]],
553 ) 765 )
554} 766}
555 767
@@ -580,3 +792,96 @@ fn match_failure_reasons() {
580 r#"Pattern wanted token '42' (INT_NUMBER), but code had token '43' (INT_NUMBER)"#, 792 r#"Pattern wanted token '42' (INT_NUMBER), but code had token '43' (INT_NUMBER)"#,
581 ); 793 );
582} 794}
795
796#[test]
797fn overlapping_possible_matches() {
798 // There are three possible matches here, however the middle one, `foo(foo(foo(42)))` shouldn't
799 // match because it overlaps with the outer match. The inner match is permitted since it's is
800 // contained entirely within the placeholder of the outer match.
801 assert_matches(
802 "foo(foo($a))",
803 "fn foo() {} fn main() {foo(foo(foo(foo(42))))}",
804 &["foo(foo(42))", "foo(foo(foo(foo(42))))"],
805 );
806}
807
808#[test]
809fn use_declaration_with_braces() {
810 // It would be OK for a path rule to match and alter a use declaration. We shouldn't mess it up
811 // though. In particular, we must not change `use foo::{baz, bar}` to `use foo::{baz,
812 // foo2::bar2}`.
813 mark::check!(use_declaration_with_braces);
814 assert_ssr_transform(
815 "foo::bar ==>> foo2::bar2",
816 r#"
817 mod foo { pub fn bar() {} pub fn baz() {} }
818 mod foo2 { pub fn bar2() {} }
819 use foo::{baz, bar};
820 fn main() { bar() }
821 "#,
822 expect![["
823 mod foo { pub fn bar() {} pub fn baz() {} }
824 mod foo2 { pub fn bar2() {} }
825 use foo::{baz, bar};
826 fn main() { foo2::bar2() }
827 "]],
828 )
829}
830
831#[test]
832fn ufcs_matches_method_call() {
833 let code = r#"
834 struct Foo {}
835 impl Foo {
836 fn new(_: i32) -> Foo { Foo {} }
837 fn do_stuff(&self, _: i32) {}
838 }
839 struct Bar {}
840 impl Bar {
841 fn new(_: i32) -> Bar { Bar {} }
842 fn do_stuff(&self, v: i32) {}
843 }
844 fn main() {
845 let b = Bar {};
846 let f = Foo {};
847 b.do_stuff(1);
848 f.do_stuff(2);
849 Foo::new(4).do_stuff(3);
850 // Too many / too few args - should never match
851 f.do_stuff(2, 10);
852 f.do_stuff();
853 }
854 "#;
855 assert_matches("Foo::do_stuff($a, $b)", code, &["f.do_stuff(2)", "Foo::new(4).do_stuff(3)"]);
856 // The arguments needs special handling in the case of a function call matching a method call
857 // and the first argument is different.
858 assert_matches("Foo::do_stuff($a, 2)", code, &["f.do_stuff(2)"]);
859 assert_matches("Foo::do_stuff(Foo::new(4), $b)", code, &["Foo::new(4).do_stuff(3)"]);
860
861 assert_ssr_transform(
862 "Foo::do_stuff(Foo::new($a), $b) ==>> Bar::new($b).do_stuff($a)",
863 code,
864 expect![[r#"
865 struct Foo {}
866 impl Foo {
867 fn new(_: i32) -> Foo { Foo {} }
868 fn do_stuff(&self, _: i32) {}
869 }
870 struct Bar {}
871 impl Bar {
872 fn new(_: i32) -> Bar { Bar {} }
873 fn do_stuff(&self, v: i32) {}
874 }
875 fn main() {
876 let b = Bar {};
877 let f = Foo {};
878 b.do_stuff(1);
879 f.do_stuff(2);
880 Bar::new(3).do_stuff(4);
881 // Too many / too few args - should never match
882 f.do_stuff(2, 10);
883 f.do_stuff();
884 }
885 "#]],
886 );
887}