1 //! This module provides an SSR assist. It is not desirable to include this
2 //! assist in ide_assists because that would require the ide_assists crate
3 //! depend on the ide_ssr crate.
4
5 use ide_assists::{Assist, AssistId, AssistKind, AssistResolveStrategy, GroupLabel};
6 use ide_db::{base_db::FileRange, label::Label, source_change::SourceChange, RootDatabase};
7
ssr_assists( db: &RootDatabase, resolve: &AssistResolveStrategy, frange: FileRange, ) -> Vec<Assist>8 pub(crate) fn ssr_assists(
9 db: &RootDatabase,
10 resolve: &AssistResolveStrategy,
11 frange: FileRange,
12 ) -> Vec<Assist> {
13 let mut ssr_assists = Vec::with_capacity(2);
14
15 let (match_finder, comment_range) = match ide_ssr::ssr_from_comment(db, frange) {
16 Some(ssr_data) => ssr_data,
17 None => return ssr_assists,
18 };
19 let id = AssistId("ssr", AssistKind::RefactorRewrite);
20
21 let (source_change_for_file, source_change_for_workspace) = if resolve.should_resolve(&id) {
22 let edits = match_finder.edits();
23
24 let source_change_for_file = {
25 let text_edit_for_file = edits.get(&frange.file_id).cloned().unwrap_or_default();
26 SourceChange::from_text_edit(frange.file_id, text_edit_for_file)
27 };
28
29 let source_change_for_workspace = SourceChange::from(match_finder.edits());
30
31 (Some(source_change_for_file), Some(source_change_for_workspace))
32 } else {
33 (None, None)
34 };
35
36 let assists = vec![
37 ("Apply SSR in file", source_change_for_file),
38 ("Apply SSR in workspace", source_change_for_workspace),
39 ];
40
41 for (label, source_change) in assists.into_iter() {
42 let assist = Assist {
43 id,
44 label: Label::new(label.to_string()),
45 group: Some(GroupLabel("Apply SSR".into())),
46 target: comment_range,
47 source_change,
48 };
49
50 ssr_assists.push(assist);
51 }
52
53 ssr_assists
54 }
55
56 #[cfg(test)]
57 mod tests {
58 use std::sync::Arc;
59
60 use expect_test::expect;
61 use ide_assists::{Assist, AssistResolveStrategy};
62 use ide_db::{
63 base_db::{fixture::WithFixture, salsa::Durability, FileRange},
64 symbol_index::SymbolsDatabase,
65 RootDatabase,
66 };
67 use rustc_hash::FxHashSet;
68
69 use super::ssr_assists;
70
get_assists(ra_fixture: &str, resolve: AssistResolveStrategy) -> Vec<Assist>71 fn get_assists(ra_fixture: &str, resolve: AssistResolveStrategy) -> Vec<Assist> {
72 let (mut db, file_id, range_or_offset) = RootDatabase::with_range_or_offset(ra_fixture);
73 let mut local_roots = FxHashSet::default();
74 local_roots.insert(ide_db::base_db::fixture::WORKSPACE);
75 db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
76 ssr_assists(&db, &resolve, FileRange { file_id, range: range_or_offset.into() })
77 }
78
79 #[test]
not_applicable_comment_not_ssr()80 fn not_applicable_comment_not_ssr() {
81 let ra_fixture = r#"
82 //- /lib.rs
83
84 // This is foo $0
85 fn foo() {}
86 "#;
87 let assists = get_assists(ra_fixture, AssistResolveStrategy::All);
88
89 assert_eq!(0, assists.len());
90 }
91
92 #[test]
resolve_edits_true()93 fn resolve_edits_true() {
94 let assists = get_assists(
95 r#"
96 //- /lib.rs
97 mod bar;
98
99 // 2 ==>> 3$0
100 fn foo() { 2 }
101
102 //- /bar.rs
103 fn bar() { 2 }
104 "#,
105 AssistResolveStrategy::All,
106 );
107
108 assert_eq!(2, assists.len());
109 let mut assists = assists.into_iter();
110
111 let apply_in_file_assist = assists.next().unwrap();
112 expect![[r#"
113 Assist {
114 id: AssistId(
115 "ssr",
116 RefactorRewrite,
117 ),
118 label: "Apply SSR in file",
119 group: Some(
120 GroupLabel(
121 "Apply SSR",
122 ),
123 ),
124 target: 10..21,
125 source_change: Some(
126 SourceChange {
127 source_file_edits: {
128 FileId(
129 0,
130 ): TextEdit {
131 indels: [
132 Indel {
133 insert: "3",
134 delete: 33..34,
135 },
136 ],
137 },
138 },
139 file_system_edits: [],
140 is_snippet: false,
141 },
142 ),
143 }
144 "#]]
145 .assert_debug_eq(&apply_in_file_assist);
146
147 let apply_in_workspace_assist = assists.next().unwrap();
148 expect![[r#"
149 Assist {
150 id: AssistId(
151 "ssr",
152 RefactorRewrite,
153 ),
154 label: "Apply SSR in workspace",
155 group: Some(
156 GroupLabel(
157 "Apply SSR",
158 ),
159 ),
160 target: 10..21,
161 source_change: Some(
162 SourceChange {
163 source_file_edits: {
164 FileId(
165 0,
166 ): TextEdit {
167 indels: [
168 Indel {
169 insert: "3",
170 delete: 33..34,
171 },
172 ],
173 },
174 FileId(
175 1,
176 ): TextEdit {
177 indels: [
178 Indel {
179 insert: "3",
180 delete: 11..12,
181 },
182 ],
183 },
184 },
185 file_system_edits: [],
186 is_snippet: false,
187 },
188 ),
189 }
190 "#]]
191 .assert_debug_eq(&apply_in_workspace_assist);
192 }
193
194 #[test]
resolve_edits_false()195 fn resolve_edits_false() {
196 let assists = get_assists(
197 r#"
198 //- /lib.rs
199 mod bar;
200
201 // 2 ==>> 3$0
202 fn foo() { 2 }
203
204 //- /bar.rs
205 fn bar() { 2 }
206 "#,
207 AssistResolveStrategy::None,
208 );
209
210 assert_eq!(2, assists.len());
211 let mut assists = assists.into_iter();
212
213 let apply_in_file_assist = assists.next().unwrap();
214 expect![[r#"
215 Assist {
216 id: AssistId(
217 "ssr",
218 RefactorRewrite,
219 ),
220 label: "Apply SSR in file",
221 group: Some(
222 GroupLabel(
223 "Apply SSR",
224 ),
225 ),
226 target: 10..21,
227 source_change: None,
228 }
229 "#]]
230 .assert_debug_eq(&apply_in_file_assist);
231
232 let apply_in_workspace_assist = assists.next().unwrap();
233 expect![[r#"
234 Assist {
235 id: AssistId(
236 "ssr",
237 RefactorRewrite,
238 ),
239 label: "Apply SSR in workspace",
240 group: Some(
241 GroupLabel(
242 "Apply SSR",
243 ),
244 ),
245 target: 10..21,
246 source_change: None,
247 }
248 "#]]
249 .assert_debug_eq(&apply_in_workspace_assist);
250 }
251 }
252