1use ide_assists::{Assist, AssistId, AssistResolveStrategy, GroupLabel};
6use ide_db::{FileRange, RootDatabase, label::Label, source_change::SourceChange};
7
8pub(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::refactor_rewrite("ssr");
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_iter(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_owned()),
45 group: Some(GroupLabel("Apply SSR".into())),
46 target: comment_range,
47 source_change,
48 command: None,
49 };
50
51 ssr_assists.push(assist);
52 }
53
54 ssr_assists
55}
56
57#[cfg(test)]
58mod tests {
59 use expect_test::expect;
60 use ide_assists::{Assist, AssistResolveStrategy};
61 use ide_db::{
62 FileRange, FxHashSet, RootDatabase, base_db::salsa::Setter as _, symbol_index::LocalRoots,
63 };
64 use test_fixture::WithFixture;
65
66 use super::ssr_assists;
67
68 fn get_assists(
69 #[rust_analyzer::rust_fixture] ra_fixture: &str,
70 resolve: AssistResolveStrategy,
71 ) -> 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(test_fixture::WORKSPACE);
75 LocalRoots::get(&db).set_roots(&mut db).to(local_roots);
76 ssr_assists(
77 &db,
78 &resolve,
79 FileRange { file_id: file_id.file_id(&db), range: range_or_offset.into() },
80 )
81 }
82
83 #[test]
84 fn not_applicable_comment_not_ssr() {
85 let ra_fixture = r#"
86 //- /lib.rs
87
88 // This is foo $0
89 fn foo() {}
90 "#;
91 let assists = get_assists(ra_fixture, AssistResolveStrategy::All);
92
93 assert_eq!(0, assists.len());
94 }
95
96 #[test]
97 fn resolve_edits_true() {
98 let assists = get_assists(
99 r#"
100 //- /lib.rs
101 mod bar;
102
103 // 2 ==>> 3$0
104 fn foo() { 2 }
105
106 //- /bar.rs
107 fn bar() { 2 }
108 "#,
109 AssistResolveStrategy::All,
110 );
111
112 assert_eq!(2, assists.len());
113 let mut assists = assists.into_iter();
114
115 let apply_in_file_assist = assists.next().unwrap();
116 expect![[r#"
117 Assist {
118 id: AssistId(
119 "ssr",
120 RefactorRewrite,
121 None,
122 ),
123 label: "Apply SSR in file",
124 group: Some(
125 GroupLabel(
126 "Apply SSR",
127 ),
128 ),
129 target: 10..21,
130 source_change: Some(
131 SourceChange {
132 source_file_edits: {
133 FileId(
134 0,
135 ): (
136 TextEdit {
137 indels: [
138 Indel {
139 insert: "3",
140 delete: 33..34,
141 },
142 ],
143 annotation: None,
144 },
145 None,
146 ),
147 },
148 file_system_edits: [],
149 is_snippet: false,
150 annotations: {},
151 next_annotation_id: 0,
152 },
153 ),
154 command: None,
155 }
156 "#]]
157 .assert_debug_eq(&apply_in_file_assist);
158
159 let apply_in_workspace_assist = assists.next().unwrap();
160 expect![[r#"
161 Assist {
162 id: AssistId(
163 "ssr",
164 RefactorRewrite,
165 None,
166 ),
167 label: "Apply SSR in workspace",
168 group: Some(
169 GroupLabel(
170 "Apply SSR",
171 ),
172 ),
173 target: 10..21,
174 source_change: Some(
175 SourceChange {
176 source_file_edits: {
177 FileId(
178 0,
179 ): (
180 TextEdit {
181 indels: [
182 Indel {
183 insert: "3",
184 delete: 33..34,
185 },
186 ],
187 annotation: None,
188 },
189 None,
190 ),
191 FileId(
192 1,
193 ): (
194 TextEdit {
195 indels: [
196 Indel {
197 insert: "3",
198 delete: 11..12,
199 },
200 ],
201 annotation: None,
202 },
203 None,
204 ),
205 },
206 file_system_edits: [],
207 is_snippet: false,
208 annotations: {},
209 next_annotation_id: 0,
210 },
211 ),
212 command: None,
213 }
214 "#]]
215 .assert_debug_eq(&apply_in_workspace_assist);
216 }
217
218 #[test]
219 fn resolve_edits_false() {
220 let assists = get_assists(
221 r#"
222 //- /lib.rs
223 mod bar;
224
225 // 2 ==>> 3$0
226 fn foo() { 2 }
227
228 //- /bar.rs
229 fn bar() { 2 }
230 "#,
231 AssistResolveStrategy::None,
232 );
233
234 assert_eq!(2, assists.len());
235 let mut assists = assists.into_iter();
236
237 let apply_in_file_assist = assists.next().unwrap();
238 expect![[r#"
239 Assist {
240 id: AssistId(
241 "ssr",
242 RefactorRewrite,
243 None,
244 ),
245 label: "Apply SSR in file",
246 group: Some(
247 GroupLabel(
248 "Apply SSR",
249 ),
250 ),
251 target: 10..21,
252 source_change: None,
253 command: None,
254 }
255 "#]]
256 .assert_debug_eq(&apply_in_file_assist);
257
258 let apply_in_workspace_assist = assists.next().unwrap();
259 expect![[r#"
260 Assist {
261 id: AssistId(
262 "ssr",
263 RefactorRewrite,
264 None,
265 ),
266 label: "Apply SSR in workspace",
267 group: Some(
268 GroupLabel(
269 "Apply SSR",
270 ),
271 ),
272 target: 10..21,
273 source_change: None,
274 command: None,
275 }
276 "#]]
277 .assert_debug_eq(&apply_in_workspace_assist);
278 }
279}