aboutsummaryrefslogtreecommitdiff
path: root/crates/ssr/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ssr/src')
-rw-r--r--crates/ssr/src/lib.rs24
-rw-r--r--crates/ssr/src/matching.rs4
-rw-r--r--crates/ssr/src/search.rs20
-rw-r--r--crates/ssr/src/tests.rs25
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;
75use crate::matching::MatchFailureReason; 75use crate::matching::MatchFailureReason;
76use hir::Semantics; 76use hir::Semantics;
77use ide_db::base_db::{FileId, FilePosition, FileRange}; 77use ide_db::base_db::{FileId, FilePosition, FileRange};
78use ide_db::source_change::SourceFileEdit;
79use resolving::ResolvedRule; 78use resolving::ResolvedRule;
80use rustc_hash::FxHashMap; 79use rustc_hash::FxHashMap;
81use syntax::{ast, AstNode, SyntaxNode, TextRange}; 80use syntax::{ast, AstNode, SyntaxNode, TextRange};
81use 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};
8use ide_db::base_db::{FileId, FileRange};
9use ide_db::{ 8use ide_db::{
9 base_db::{FileId, FileRange},
10 defs::Definition, 10 defs::Definition,
11 search::{Reference, SearchScope}, 11 search::{SearchScope, UsageSearchResult},
12}; 12};
13use rustc_hash::FxHashSet; 13use rustc_hash::FxHashSet;
14use syntax::{ast, AstNode, SyntaxKind, SyntaxNode}; 14use 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)]
22pub(crate) struct UsageCache { 22pub(crate) struct UsageCache {
23 usages: Vec<(Definition, Vec<Reference>)>, 23 usages: Vec<(Definition, UsageSearchResult)>,
24} 24}
25 25
26impl<'db> MatchFinder<'db> { 26impl<'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
252impl UsageCache { 252impl 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.
64pub(crate) fn single_file(code: &str) -> (ide_db::RootDatabase, FilePosition, Vec<FileRange>) { 64pub(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]
708fn replace_path_in_different_contexts() { 707fn 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)