diff options
author | David Lattimore <[email protected]> | 2020-07-29 02:44:01 +0100 |
---|---|---|
committer | David Lattimore <[email protected]> | 2020-07-29 06:06:58 +0100 |
commit | cf55806257776baf7db6b02d260bdaa9e851c7d4 (patch) | |
tree | 6827c094a4a27631ee9b1b97d98a8ac9c0a56aac /crates/ra_ssr/src/tests.rs | |
parent | 5a8124273dd663f7f1ed43b53defc4a2c52dbc12 (diff) |
SSR: Restrict to current selection if any
The selection is also used to avoid unnecessary work, but only to the
file level. Further restricting unnecessary work is left for later.
Diffstat (limited to 'crates/ra_ssr/src/tests.rs')
-rw-r--r-- | crates/ra_ssr/src/tests.rs | 96 |
1 files changed, 79 insertions, 17 deletions
diff --git a/crates/ra_ssr/src/tests.rs b/crates/ra_ssr/src/tests.rs index 18ef2506a..6a44ef378 100644 --- a/crates/ra_ssr/src/tests.rs +++ b/crates/ra_ssr/src/tests.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | use crate::{MatchFinder, SsrRule}; | 1 | use crate::{MatchFinder, SsrRule}; |
2 | use expect::{expect, Expect}; | 2 | use expect::{expect, Expect}; |
3 | use ra_db::{salsa::Durability, FileId, FilePosition, SourceDatabaseExt}; | 3 | use ra_db::{salsa::Durability, FileId, FilePosition, FileRange, SourceDatabaseExt}; |
4 | use rustc_hash::FxHashSet; | 4 | use rustc_hash::FxHashSet; |
5 | use std::sync::Arc; | 5 | use std::sync::Arc; |
6 | use test_utils::mark; | 6 | use test_utils::{mark, RangeOrOffset}; |
7 | 7 | ||
8 | fn parse_error_text(query: &str) -> String { | 8 | fn parse_error_text(query: &str) -> String { |
9 | format!("{}", query.parse::<SsrRule>().unwrap_err()) | 9 | format!("{}", query.parse::<SsrRule>().unwrap_err()) |
@@ -60,20 +60,32 @@ fn parser_undefined_placeholder_in_replacement() { | |||
60 | } | 60 | } |
61 | 61 | ||
62 | /// `code` may optionally contain a cursor marker `<|>`. If it doesn't, then the position will be | 62 | /// `code` may optionally contain a cursor marker `<|>`. If it doesn't, then the position will be |
63 | /// the start of the file. | 63 | /// the start of the file. If there's a second cursor marker, then we'll return a single range. |
64 | pub(crate) fn single_file(code: &str) -> (ra_ide_db::RootDatabase, FilePosition) { | 64 | pub(crate) fn single_file(code: &str) -> (ra_ide_db::RootDatabase, FilePosition, Vec<FileRange>) { |
65 | use ra_db::fixture::WithFixture; | 65 | use ra_db::fixture::WithFixture; |
66 | use ra_ide_db::symbol_index::SymbolsDatabase; | 66 | use ra_ide_db::symbol_index::SymbolsDatabase; |
67 | let (mut db, position) = if code.contains(test_utils::CURSOR_MARKER) { | 67 | let (mut db, file_id, range_or_offset) = if code.contains(test_utils::CURSOR_MARKER) { |
68 | ra_ide_db::RootDatabase::with_position(code) | 68 | ra_ide_db::RootDatabase::with_range_or_offset(code) |
69 | } else { | 69 | } else { |
70 | let (db, file_id) = ra_ide_db::RootDatabase::with_single_file(code); | 70 | let (db, file_id) = ra_ide_db::RootDatabase::with_single_file(code); |
71 | (db, FilePosition { file_id, offset: 0.into() }) | 71 | (db, file_id, RangeOrOffset::Offset(0.into())) |
72 | }; | 72 | }; |
73 | let selections; | ||
74 | let position; | ||
75 | match range_or_offset { | ||
76 | RangeOrOffset::Range(range) => { | ||
77 | position = FilePosition { file_id, offset: range.start() }; | ||
78 | selections = vec![FileRange { file_id, range: range }]; | ||
79 | } | ||
80 | RangeOrOffset::Offset(offset) => { | ||
81 | position = FilePosition { file_id, offset }; | ||
82 | selections = vec![]; | ||
83 | } | ||
84 | } | ||
73 | let mut local_roots = FxHashSet::default(); | 85 | let mut local_roots = FxHashSet::default(); |
74 | local_roots.insert(ra_db::fixture::WORKSPACE); | 86 | local_roots.insert(ra_db::fixture::WORKSPACE); |
75 | db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH); | 87 | db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH); |
76 | (db, position) | 88 | (db, position, selections) |
77 | } | 89 | } |
78 | 90 | ||
79 | fn assert_ssr_transform(rule: &str, input: &str, expected: Expect) { | 91 | fn assert_ssr_transform(rule: &str, input: &str, expected: Expect) { |
@@ -81,8 +93,8 @@ fn assert_ssr_transform(rule: &str, input: &str, expected: Expect) { | |||
81 | } | 93 | } |
82 | 94 | ||
83 | fn assert_ssr_transforms(rules: &[&str], input: &str, expected: Expect) { | 95 | fn assert_ssr_transforms(rules: &[&str], input: &str, expected: Expect) { |
84 | let (db, position) = single_file(input); | 96 | let (db, position, selections) = single_file(input); |
85 | let mut match_finder = MatchFinder::in_context(&db, position); | 97 | let mut match_finder = MatchFinder::in_context(&db, position, selections); |
86 | for rule in rules { | 98 | for rule in rules { |
87 | let rule: SsrRule = rule.parse().unwrap(); | 99 | let rule: SsrRule = rule.parse().unwrap(); |
88 | match_finder.add_rule(rule).unwrap(); | 100 | match_finder.add_rule(rule).unwrap(); |
@@ -112,8 +124,8 @@ fn print_match_debug_info(match_finder: &MatchFinder, file_id: FileId, snippet: | |||
112 | } | 124 | } |
113 | 125 | ||
114 | fn assert_matches(pattern: &str, code: &str, expected: &[&str]) { | 126 | fn assert_matches(pattern: &str, code: &str, expected: &[&str]) { |
115 | let (db, position) = single_file(code); | 127 | let (db, position, selections) = single_file(code); |
116 | let mut match_finder = MatchFinder::in_context(&db, position); | 128 | let mut match_finder = MatchFinder::in_context(&db, position, selections); |
117 | match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap(); | 129 | match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap(); |
118 | let matched_strings: Vec<String> = | 130 | let matched_strings: Vec<String> = |
119 | match_finder.matches().flattened().matches.iter().map(|m| m.matched_text()).collect(); | 131 | match_finder.matches().flattened().matches.iter().map(|m| m.matched_text()).collect(); |
@@ -124,8 +136,8 @@ fn assert_matches(pattern: &str, code: &str, expected: &[&str]) { | |||
124 | } | 136 | } |
125 | 137 | ||
126 | fn assert_no_match(pattern: &str, code: &str) { | 138 | fn assert_no_match(pattern: &str, code: &str) { |
127 | let (db, position) = single_file(code); | 139 | let (db, position, selections) = single_file(code); |
128 | let mut match_finder = MatchFinder::in_context(&db, position); | 140 | let mut match_finder = MatchFinder::in_context(&db, position, selections); |
129 | match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap(); | 141 | match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap(); |
130 | let matches = match_finder.matches().flattened().matches; | 142 | let matches = match_finder.matches().flattened().matches; |
131 | if !matches.is_empty() { | 143 | if !matches.is_empty() { |
@@ -135,8 +147,8 @@ fn assert_no_match(pattern: &str, code: &str) { | |||
135 | } | 147 | } |
136 | 148 | ||
137 | fn assert_match_failure_reason(pattern: &str, code: &str, snippet: &str, expected_reason: &str) { | 149 | fn assert_match_failure_reason(pattern: &str, code: &str, snippet: &str, expected_reason: &str) { |
138 | let (db, position) = single_file(code); | 150 | let (db, position, selections) = single_file(code); |
139 | let mut match_finder = MatchFinder::in_context(&db, position); | 151 | let mut match_finder = MatchFinder::in_context(&db, position, selections); |
140 | match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap(); | 152 | match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap(); |
141 | let mut reasons = Vec::new(); | 153 | let mut reasons = Vec::new(); |
142 | for d in match_finder.debug_where_text_equal(position.file_id, snippet) { | 154 | for d in match_finder.debug_where_text_equal(position.file_id, snippet) { |
@@ -490,9 +502,10 @@ fn no_match_split_expression() { | |||
490 | 502 | ||
491 | #[test] | 503 | #[test] |
492 | fn replace_function_call() { | 504 | fn replace_function_call() { |
505 | // This test also makes sure that we ignore empty-ranges. | ||
493 | assert_ssr_transform( | 506 | assert_ssr_transform( |
494 | "foo() ==>> bar()", | 507 | "foo() ==>> bar()", |
495 | "fn foo() {} fn bar() {} fn f1() {foo(); foo();}", | 508 | "fn foo() {<|><|>} fn bar() {} fn f1() {foo(); foo();}", |
496 | expect![["fn foo() {} fn bar() {} fn f1() {bar(); bar();}"]], | 509 | expect![["fn foo() {} fn bar() {} fn f1() {bar(); bar();}"]], |
497 | ); | 510 | ); |
498 | } | 511 | } |
@@ -922,3 +935,52 @@ fn replace_local_variable_reference() { | |||
922 | "#]], | 935 | "#]], |
923 | ) | 936 | ) |
924 | } | 937 | } |
938 | |||
939 | #[test] | ||
940 | fn replace_path_within_selection() { | ||
941 | assert_ssr_transform( | ||
942 | "foo ==>> bar", | ||
943 | r#" | ||
944 | fn main() { | ||
945 | let foo = 41; | ||
946 | let bar = 42; | ||
947 | do_stuff(foo); | ||
948 | do_stuff(foo);<|> | ||
949 | do_stuff(foo); | ||
950 | do_stuff(foo);<|> | ||
951 | do_stuff(foo); | ||
952 | }"#, | ||
953 | expect![[r#" | ||
954 | fn main() { | ||
955 | let foo = 41; | ||
956 | let bar = 42; | ||
957 | do_stuff(foo); | ||
958 | do_stuff(foo); | ||
959 | do_stuff(bar); | ||
960 | do_stuff(bar); | ||
961 | do_stuff(foo); | ||
962 | }"#]], | ||
963 | ); | ||
964 | } | ||
965 | |||
966 | #[test] | ||
967 | fn replace_nonpath_within_selection() { | ||
968 | mark::check!(replace_nonpath_within_selection); | ||
969 | assert_ssr_transform( | ||
970 | "$a + $b ==>> $b * $a", | ||
971 | r#" | ||
972 | fn main() { | ||
973 | let v = 1 + 2;<|> | ||
974 | let v2 = 3 + 3; | ||
975 | let v3 = 4 + 5;<|> | ||
976 | let v4 = 6 + 7; | ||
977 | }"#, | ||
978 | expect![[r#" | ||
979 | fn main() { | ||
980 | let v = 1 + 2; | ||
981 | let v2 = 3 * 3; | ||
982 | let v3 = 5 * 4; | ||
983 | let v4 = 6 + 7; | ||
984 | }"#]], | ||
985 | ); | ||
986 | } | ||