ide/
ssr.rs

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
5use 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}