diff options
Diffstat (limited to 'crates/ssr/src')
-rw-r--r-- | crates/ssr/src/lib.rs | 24 | ||||
-rw-r--r-- | crates/ssr/src/matching.rs | 4 | ||||
-rw-r--r-- | crates/ssr/src/search.rs | 20 | ||||
-rw-r--r-- | crates/ssr/src/tests.rs | 25 |
4 files changed, 39 insertions, 34 deletions
diff --git a/crates/ssr/src/lib.rs b/crates/ssr/src/lib.rs index 747ce495d..a97fc8bca 100644 --- a/crates/ssr/src/lib.rs +++ b/crates/ssr/src/lib.rs | |||
@@ -75,10 +75,10 @@ pub use crate::matching::Match; | |||
75 | use crate::matching::MatchFailureReason; | 75 | use crate::matching::MatchFailureReason; |
76 | use hir::Semantics; | 76 | use hir::Semantics; |
77 | use ide_db::base_db::{FileId, FilePosition, FileRange}; | 77 | use ide_db::base_db::{FileId, FilePosition, FileRange}; |
78 | use ide_db::source_change::SourceFileEdit; | ||
79 | use resolving::ResolvedRule; | 78 | use resolving::ResolvedRule; |
80 | use rustc_hash::FxHashMap; | 79 | use rustc_hash::FxHashMap; |
81 | use syntax::{ast, AstNode, SyntaxNode, TextRange}; | 80 | use syntax::{ast, AstNode, SyntaxNode, TextRange}; |
81 | use text_edit::TextEdit; | ||
82 | 82 | ||
83 | // A structured search replace rule. Create by calling `parse` on a str. | 83 | // A structured search replace rule. Create by calling `parse` on a str. |
84 | #[derive(Debug)] | 84 | #[derive(Debug)] |
@@ -159,7 +159,7 @@ impl<'db> MatchFinder<'db> { | |||
159 | } | 159 | } |
160 | 160 | ||
161 | /// Finds matches for all added rules and returns edits for all found matches. | 161 | /// Finds matches for all added rules and returns edits for all found matches. |
162 | pub fn edits(&self) -> Vec<SourceFileEdit> { | 162 | pub fn edits(&self) -> FxHashMap<FileId, TextEdit> { |
163 | use ide_db::base_db::SourceDatabaseExt; | 163 | use ide_db::base_db::SourceDatabaseExt; |
164 | let mut matches_by_file = FxHashMap::default(); | 164 | let mut matches_by_file = FxHashMap::default(); |
165 | for m in self.matches().matches { | 165 | for m in self.matches().matches { |
@@ -169,13 +169,19 @@ impl<'db> MatchFinder<'db> { | |||
169 | .matches | 169 | .matches |
170 | .push(m); | 170 | .push(m); |
171 | } | 171 | } |
172 | let mut edits = vec![]; | 172 | matches_by_file |
173 | for (file_id, matches) in matches_by_file { | 173 | .into_iter() |
174 | let edit = | 174 | .map(|(file_id, matches)| { |
175 | replacing::matches_to_edit(&matches, &self.sema.db.file_text(file_id), &self.rules); | 175 | ( |
176 | edits.push(SourceFileEdit { file_id, edit }); | 176 | file_id, |
177 | } | 177 | replacing::matches_to_edit( |
178 | edits | 178 | &matches, |
179 | &self.sema.db.file_text(file_id), | ||
180 | &self.rules, | ||
181 | ), | ||
182 | ) | ||
183 | }) | ||
184 | .collect() | ||
179 | } | 185 | } |
180 | 186 | ||
181 | /// Adds a search pattern. For use if you intend to only call `find_matches_in_file`. If you | 187 | /// Adds a search pattern. For use if you intend to only call `find_matches_in_file`. If you |
diff --git a/crates/ssr/src/matching.rs b/crates/ssr/src/matching.rs index 6cf831431..42d313f91 100644 --- a/crates/ssr/src/matching.rs +++ b/crates/ssr/src/matching.rs | |||
@@ -810,9 +810,9 @@ mod tests { | |||
810 | 810 | ||
811 | let edits = match_finder.edits(); | 811 | let edits = match_finder.edits(); |
812 | assert_eq!(edits.len(), 1); | 812 | assert_eq!(edits.len(), 1); |
813 | let edit = &edits[0]; | 813 | let edit = &edits[&position.file_id]; |
814 | let mut after = input.to_string(); | 814 | let mut after = input.to_string(); |
815 | edit.edit.apply(&mut after); | 815 | edit.apply(&mut after); |
816 | assert_eq!(after, "fn foo() {} fn bar() {} fn main() { bar(1+2); }"); | 816 | assert_eq!(after, "fn foo() {} fn bar() {} fn main() { bar(1+2); }"); |
817 | } | 817 | } |
818 | } | 818 | } |
diff --git a/crates/ssr/src/search.rs b/crates/ssr/src/search.rs index 44b5db029..836eb94b2 100644 --- a/crates/ssr/src/search.rs +++ b/crates/ssr/src/search.rs | |||
@@ -5,10 +5,10 @@ use crate::{ | |||
5 | resolving::{ResolvedPath, ResolvedPattern, ResolvedRule}, | 5 | resolving::{ResolvedPath, ResolvedPattern, ResolvedRule}, |
6 | Match, MatchFinder, | 6 | Match, MatchFinder, |
7 | }; | 7 | }; |
8 | use ide_db::base_db::{FileId, FileRange}; | ||
9 | use ide_db::{ | 8 | use ide_db::{ |
9 | base_db::{FileId, FileRange}, | ||
10 | defs::Definition, | 10 | defs::Definition, |
11 | search::{Reference, SearchScope}, | 11 | search::{SearchScope, UsageSearchResult}, |
12 | }; | 12 | }; |
13 | use rustc_hash::FxHashSet; | 13 | use rustc_hash::FxHashSet; |
14 | use syntax::{ast, AstNode, SyntaxKind, SyntaxNode}; | 14 | use syntax::{ast, AstNode, SyntaxKind, SyntaxNode}; |
@@ -20,7 +20,7 @@ use test_utils::mark; | |||
20 | /// them more than once. | 20 | /// them more than once. |
21 | #[derive(Default)] | 21 | #[derive(Default)] |
22 | pub(crate) struct UsageCache { | 22 | pub(crate) struct UsageCache { |
23 | usages: Vec<(Definition, Vec<Reference>)>, | 23 | usages: Vec<(Definition, UsageSearchResult)>, |
24 | } | 24 | } |
25 | 25 | ||
26 | impl<'db> MatchFinder<'db> { | 26 | impl<'db> MatchFinder<'db> { |
@@ -58,8 +58,8 @@ impl<'db> MatchFinder<'db> { | |||
58 | ) { | 58 | ) { |
59 | if let Some(resolved_path) = pick_path_for_usages(pattern) { | 59 | if let Some(resolved_path) = pick_path_for_usages(pattern) { |
60 | let definition: Definition = resolved_path.resolution.clone().into(); | 60 | let definition: Definition = resolved_path.resolution.clone().into(); |
61 | for reference in self.find_usages(usage_cache, definition) { | 61 | for file_range in self.find_usages(usage_cache, definition).file_ranges() { |
62 | if let Some(node_to_match) = self.find_node_to_match(resolved_path, reference) { | 62 | if let Some(node_to_match) = self.find_node_to_match(resolved_path, file_range) { |
63 | if !is_search_permitted_ancestors(&node_to_match) { | 63 | if !is_search_permitted_ancestors(&node_to_match) { |
64 | mark::hit!(use_declaration_with_braces); | 64 | mark::hit!(use_declaration_with_braces); |
65 | continue; | 65 | continue; |
@@ -73,11 +73,11 @@ impl<'db> MatchFinder<'db> { | |||
73 | fn find_node_to_match( | 73 | fn find_node_to_match( |
74 | &self, | 74 | &self, |
75 | resolved_path: &ResolvedPath, | 75 | resolved_path: &ResolvedPath, |
76 | reference: &Reference, | 76 | file_range: FileRange, |
77 | ) -> Option<SyntaxNode> { | 77 | ) -> Option<SyntaxNode> { |
78 | let file = self.sema.parse(reference.file_range.file_id); | 78 | let file = self.sema.parse(file_range.file_id); |
79 | let depth = resolved_path.depth as usize; | 79 | let depth = resolved_path.depth as usize; |
80 | let offset = reference.file_range.range.start(); | 80 | let offset = file_range.range.start(); |
81 | if let Some(path) = | 81 | if let Some(path) = |
82 | self.sema.find_node_at_offset_with_descend::<ast::Path>(file.syntax(), offset) | 82 | self.sema.find_node_at_offset_with_descend::<ast::Path>(file.syntax(), offset) |
83 | { | 83 | { |
@@ -108,7 +108,7 @@ impl<'db> MatchFinder<'db> { | |||
108 | &self, | 108 | &self, |
109 | usage_cache: &'a mut UsageCache, | 109 | usage_cache: &'a mut UsageCache, |
110 | definition: Definition, | 110 | definition: Definition, |
111 | ) -> &'a [Reference] { | 111 | ) -> &'a UsageSearchResult { |
112 | // Logically if a lookup succeeds we should just return it. Unfortunately returning it would | 112 | // Logically if a lookup succeeds we should just return it. Unfortunately returning it would |
113 | // extend the lifetime of the borrow, then we wouldn't be able to do the insertion on a | 113 | // extend the lifetime of the borrow, then we wouldn't be able to do the insertion on a |
114 | // cache miss. This is a limitation of NLL and is fixed with Polonius. For now we do two | 114 | // cache miss. This is a limitation of NLL and is fixed with Polonius. For now we do two |
@@ -250,7 +250,7 @@ fn is_search_permitted(node: &SyntaxNode) -> bool { | |||
250 | } | 250 | } |
251 | 251 | ||
252 | impl UsageCache { | 252 | impl UsageCache { |
253 | fn find(&mut self, definition: &Definition) -> Option<&[Reference]> { | 253 | fn find(&mut self, definition: &Definition) -> Option<&UsageSearchResult> { |
254 | // We expect a very small number of cache entries (generally 1), so a linear scan should be | 254 | // We expect a very small number of cache entries (generally 1), so a linear scan should be |
255 | // fast enough and avoids the need to implement Hash for Definition. | 255 | // fast enough and avoids the need to implement Hash for Definition. |
256 | for (d, refs) in &self.usages { | 256 | for (d, refs) in &self.usages { |
diff --git a/crates/ssr/src/tests.rs b/crates/ssr/src/tests.rs index db9cb8ca1..a3ea44f23 100644 --- a/crates/ssr/src/tests.rs +++ b/crates/ssr/src/tests.rs | |||
@@ -59,7 +59,7 @@ fn parser_undefined_placeholder_in_replacement() { | |||
59 | ); | 59 | ); |
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 `$0`. If it doesn't, then the position will be |
63 | /// the start of the file. If there's a second cursor marker, then we'll return a single range. | 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) -> (ide_db::RootDatabase, FilePosition, Vec<FileRange>) { | 64 | pub(crate) fn single_file(code: &str) -> (ide_db::RootDatabase, FilePosition, Vec<FileRange>) { |
65 | use ide_db::base_db::fixture::WithFixture; | 65 | use ide_db::base_db::fixture::WithFixture; |
@@ -103,11 +103,10 @@ fn assert_ssr_transforms(rules: &[&str], input: &str, expected: Expect) { | |||
103 | if edits.is_empty() { | 103 | if edits.is_empty() { |
104 | panic!("No edits were made"); | 104 | panic!("No edits were made"); |
105 | } | 105 | } |
106 | assert_eq!(edits[0].file_id, position.file_id); | ||
107 | // Note, db.file_text is not necessarily the same as `input`, since fixture parsing alters | 106 | // Note, db.file_text is not necessarily the same as `input`, since fixture parsing alters |
108 | // stuff. | 107 | // stuff. |
109 | let mut actual = db.file_text(position.file_id).to_string(); | 108 | let mut actual = db.file_text(position.file_id).to_string(); |
110 | edits[0].edit.apply(&mut actual); | 109 | edits[&position.file_id].apply(&mut actual); |
111 | expected.assert_eq(&actual); | 110 | expected.assert_eq(&actual); |
112 | } | 111 | } |
113 | 112 | ||
@@ -596,7 +595,7 @@ fn replace_function_call() { | |||
596 | // This test also makes sure that we ignore empty-ranges. | 595 | // This test also makes sure that we ignore empty-ranges. |
597 | assert_ssr_transform( | 596 | assert_ssr_transform( |
598 | "foo() ==>> bar()", | 597 | "foo() ==>> bar()", |
599 | "fn foo() {<|><|>} fn bar() {} fn f1() {foo(); foo();}", | 598 | "fn foo() {$0$0} fn bar() {} fn f1() {foo(); foo();}", |
600 | expect![["fn foo() {} fn bar() {} fn f1() {bar(); bar();}"]], | 599 | expect![["fn foo() {} fn bar() {} fn f1() {bar(); bar();}"]], |
601 | ); | 600 | ); |
602 | } | 601 | } |
@@ -706,7 +705,7 @@ fn replace_associated_trait_constant() { | |||
706 | 705 | ||
707 | #[test] | 706 | #[test] |
708 | fn replace_path_in_different_contexts() { | 707 | fn replace_path_in_different_contexts() { |
709 | // Note the <|> inside module a::b which marks the point where the rule is interpreted. We | 708 | // Note the $0 inside module a::b which marks the point where the rule is interpreted. We |
710 | // replace foo with bar, but both need different path qualifiers in different contexts. In f4, | 709 | // replace foo with bar, but both need different path qualifiers in different contexts. In f4, |
711 | // foo is unqualified because of a use statement, however the replacement needs to be fully | 710 | // foo is unqualified because of a use statement, however the replacement needs to be fully |
712 | // qualified. | 711 | // qualified. |
@@ -714,7 +713,7 @@ fn replace_path_in_different_contexts() { | |||
714 | "c::foo() ==>> c::bar()", | 713 | "c::foo() ==>> c::bar()", |
715 | r#" | 714 | r#" |
716 | mod a { | 715 | mod a { |
717 | pub mod b {<|> | 716 | pub mod b {$0 |
718 | pub mod c { | 717 | pub mod c { |
719 | pub fn foo() {} | 718 | pub fn foo() {} |
720 | pub fn bar() {} | 719 | pub fn bar() {} |
@@ -1096,7 +1095,7 @@ fn pattern_is_a_single_segment_path() { | |||
1096 | fn f1() -> i32 { | 1095 | fn f1() -> i32 { |
1097 | let foo = 1; | 1096 | let foo = 1; |
1098 | let bar = 2; | 1097 | let bar = 2; |
1099 | foo<|> | 1098 | foo$0 |
1100 | } | 1099 | } |
1101 | "#, | 1100 | "#, |
1102 | expect![[r#" | 1101 | expect![[r#" |
@@ -1128,7 +1127,7 @@ fn replace_local_variable_reference() { | |||
1128 | let foo = 5; | 1127 | let foo = 5; |
1129 | res += foo + 1; | 1128 | res += foo + 1; |
1130 | let foo = 10; | 1129 | let foo = 10; |
1131 | res += foo + 2;<|> | 1130 | res += foo + 2;$0 |
1132 | res += foo + 3; | 1131 | res += foo + 3; |
1133 | let foo = 15; | 1132 | let foo = 15; |
1134 | res += foo + 4; | 1133 | res += foo + 4; |
@@ -1160,9 +1159,9 @@ fn replace_path_within_selection() { | |||
1160 | let foo = 41; | 1159 | let foo = 41; |
1161 | let bar = 42; | 1160 | let bar = 42; |
1162 | do_stuff(foo); | 1161 | do_stuff(foo); |
1163 | do_stuff(foo);<|> | 1162 | do_stuff(foo);$0 |
1164 | do_stuff(foo); | 1163 | do_stuff(foo); |
1165 | do_stuff(foo);<|> | 1164 | do_stuff(foo);$0 |
1166 | do_stuff(foo); | 1165 | do_stuff(foo); |
1167 | }"#, | 1166 | }"#, |
1168 | expect![[r#" | 1167 | expect![[r#" |
@@ -1185,9 +1184,9 @@ fn replace_nonpath_within_selection() { | |||
1185 | "$a + $b ==>> $b * $a", | 1184 | "$a + $b ==>> $b * $a", |
1186 | r#" | 1185 | r#" |
1187 | fn main() { | 1186 | fn main() { |
1188 | let v = 1 + 2;<|> | 1187 | let v = 1 + 2;$0 |
1189 | let v2 = 3 + 3; | 1188 | let v2 = 3 + 3; |
1190 | let v3 = 4 + 5;<|> | 1189 | let v3 = 4 + 5;$0 |
1191 | let v4 = 6 + 7; | 1190 | let v4 = 6 + 7; |
1192 | }"#, | 1191 | }"#, |
1193 | expect![[r#" | 1192 | expect![[r#" |
@@ -1212,7 +1211,7 @@ fn replace_self() { | |||
1212 | fn bar(_: &S1) {} | 1211 | fn bar(_: &S1) {} |
1213 | impl S1 { | 1212 | impl S1 { |
1214 | fn f1(&self) { | 1213 | fn f1(&self) { |
1215 | foo(self)<|> | 1214 | foo(self)$0 |
1216 | } | 1215 | } |
1217 | fn f2(&self) { | 1216 | fn f2(&self) { |
1218 | foo(self) | 1217 | foo(self) |