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