diff options
author | Aleksey Kladov <[email protected]> | 2020-10-15 16:07:53 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-10-15 16:10:06 +0100 |
commit | 3086fb2ef4064ab7daa8194a8d57c742849ca900 (patch) | |
tree | bc5cb9aa891a7036c920a0f60c2d5f9c24ec0135 /crates/ide/src/diagnostics.rs | |
parent | 1022672af0467edf480f50398989c3f8016ccd10 (diff) |
Move field_shorthand to a separate module
Diffstat (limited to 'crates/ide/src/diagnostics.rs')
-rw-r--r-- | crates/ide/src/diagnostics.rs | 201 |
1 files changed, 5 insertions, 196 deletions
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index c36c321f2..1e5ea4617 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -5,6 +5,7 @@ | |||
5 | //! original files. So we need to map the ranges. | 5 | //! original files. So we need to map the ranges. |
6 | 6 | ||
7 | mod fixes; | 7 | mod fixes; |
8 | mod field_shorthand; | ||
8 | 9 | ||
9 | use std::cell::RefCell; | 10 | use std::cell::RefCell; |
10 | 11 | ||
@@ -15,7 +16,7 @@ use itertools::Itertools; | |||
15 | use rustc_hash::FxHashSet; | 16 | use rustc_hash::FxHashSet; |
16 | use syntax::{ | 17 | use syntax::{ |
17 | ast::{self, AstNode}, | 18 | ast::{self, AstNode}, |
18 | match_ast, SyntaxNode, TextRange, T, | 19 | SyntaxNode, TextRange, T, |
19 | }; | 20 | }; |
20 | use text_edit::TextEdit; | 21 | use text_edit::TextEdit; |
21 | 22 | ||
@@ -80,7 +81,7 @@ pub(crate) fn diagnostics( | |||
80 | 81 | ||
81 | for node in parse.tree().syntax().descendants() { | 82 | for node in parse.tree().syntax().descendants() { |
82 | check_unnecessary_braces_in_use_statement(&mut res, file_id, &node); | 83 | check_unnecessary_braces_in_use_statement(&mut res, file_id, &node); |
83 | check_field_shorthand(&mut res, file_id, &node); | 84 | field_shorthand::check(&mut res, file_id, &node); |
84 | } | 85 | } |
85 | let res = RefCell::new(res); | 86 | let res = RefCell::new(res); |
86 | let sink_builder = DiagnosticSinkBuilder::new() | 87 | let sink_builder = DiagnosticSinkBuilder::new() |
@@ -188,100 +189,6 @@ fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement( | |||
188 | None | 189 | None |
189 | } | 190 | } |
190 | 191 | ||
191 | fn check_field_shorthand(acc: &mut Vec<Diagnostic>, file_id: FileId, node: &SyntaxNode) { | ||
192 | match_ast! { | ||
193 | match node { | ||
194 | ast::RecordExpr(it) => check_expr_field_shorthand(acc, file_id, it), | ||
195 | ast::RecordPat(it) => check_pat_field_shorthand(acc, file_id, it), | ||
196 | _ => () | ||
197 | } | ||
198 | }; | ||
199 | } | ||
200 | |||
201 | fn check_expr_field_shorthand( | ||
202 | acc: &mut Vec<Diagnostic>, | ||
203 | file_id: FileId, | ||
204 | record_expr: ast::RecordExpr, | ||
205 | ) { | ||
206 | let record_field_list = match record_expr.record_expr_field_list() { | ||
207 | Some(it) => it, | ||
208 | None => return, | ||
209 | }; | ||
210 | for record_field in record_field_list.fields() { | ||
211 | let (name_ref, expr) = match record_field.name_ref().zip(record_field.expr()) { | ||
212 | Some(it) => it, | ||
213 | None => continue, | ||
214 | }; | ||
215 | |||
216 | let field_name = name_ref.syntax().text().to_string(); | ||
217 | let field_expr = expr.syntax().text().to_string(); | ||
218 | let field_name_is_tup_index = name_ref.as_tuple_field().is_some(); | ||
219 | if field_name != field_expr || field_name_is_tup_index { | ||
220 | continue; | ||
221 | } | ||
222 | |||
223 | let mut edit_builder = TextEdit::builder(); | ||
224 | edit_builder.delete(record_field.syntax().text_range()); | ||
225 | edit_builder.insert(record_field.syntax().text_range().start(), field_name); | ||
226 | let edit = edit_builder.finish(); | ||
227 | |||
228 | let field_range = record_field.syntax().text_range(); | ||
229 | acc.push(Diagnostic { | ||
230 | // name: None, | ||
231 | range: field_range, | ||
232 | message: "Shorthand struct initialization".to_string(), | ||
233 | severity: Severity::WeakWarning, | ||
234 | fix: Some(Fix::new( | ||
235 | "Use struct shorthand initialization", | ||
236 | SourceFileEdit { file_id, edit }.into(), | ||
237 | field_range, | ||
238 | )), | ||
239 | }); | ||
240 | } | ||
241 | } | ||
242 | |||
243 | fn check_pat_field_shorthand( | ||
244 | acc: &mut Vec<Diagnostic>, | ||
245 | file_id: FileId, | ||
246 | record_pat: ast::RecordPat, | ||
247 | ) { | ||
248 | let record_pat_field_list = match record_pat.record_pat_field_list() { | ||
249 | Some(it) => it, | ||
250 | None => return, | ||
251 | }; | ||
252 | for record_pat_field in record_pat_field_list.fields() { | ||
253 | let (name_ref, pat) = match record_pat_field.name_ref().zip(record_pat_field.pat()) { | ||
254 | Some(it) => it, | ||
255 | None => continue, | ||
256 | }; | ||
257 | |||
258 | let field_name = name_ref.syntax().text().to_string(); | ||
259 | let field_pat = pat.syntax().text().to_string(); | ||
260 | let field_name_is_tup_index = name_ref.as_tuple_field().is_some(); | ||
261 | if field_name != field_pat || field_name_is_tup_index { | ||
262 | continue; | ||
263 | } | ||
264 | |||
265 | let mut edit_builder = TextEdit::builder(); | ||
266 | edit_builder.delete(record_pat_field.syntax().text_range()); | ||
267 | edit_builder.insert(record_pat_field.syntax().text_range().start(), field_name); | ||
268 | let edit = edit_builder.finish(); | ||
269 | |||
270 | let field_range = record_pat_field.syntax().text_range(); | ||
271 | acc.push(Diagnostic { | ||
272 | // name: None, | ||
273 | range: field_range, | ||
274 | message: "Shorthand struct pattern".to_string(), | ||
275 | severity: Severity::WeakWarning, | ||
276 | fix: Some(Fix::new( | ||
277 | "Use struct field shorthand", | ||
278 | SourceFileEdit { file_id, edit }.into(), | ||
279 | field_range, | ||
280 | )), | ||
281 | }); | ||
282 | } | ||
283 | } | ||
284 | |||
285 | #[cfg(test)] | 192 | #[cfg(test)] |
286 | mod tests { | 193 | mod tests { |
287 | use expect_test::{expect, Expect}; | 194 | use expect_test::{expect, Expect}; |
@@ -295,7 +202,7 @@ mod tests { | |||
295 | /// * a diagnostic is produced | 202 | /// * a diagnostic is produced |
296 | /// * this diagnostic fix trigger range touches the input cursor position | 203 | /// * this diagnostic fix trigger range touches the input cursor position |
297 | /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied | 204 | /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied |
298 | fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) { | 205 | pub(super) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) { |
299 | let after = trim_indent(ra_fixture_after); | 206 | let after = trim_indent(ra_fixture_after); |
300 | 207 | ||
301 | let (analysis, file_position) = fixture::position(ra_fixture_before); | 208 | let (analysis, file_position) = fixture::position(ra_fixture_before); |
@@ -377,7 +284,7 @@ mod tests { | |||
377 | 284 | ||
378 | /// Takes a multi-file input fixture with annotated cursor position and checks that no diagnostics | 285 | /// Takes a multi-file input fixture with annotated cursor position and checks that no diagnostics |
379 | /// apply to the file containing the cursor. | 286 | /// apply to the file containing the cursor. |
380 | fn check_no_diagnostics(ra_fixture: &str) { | 287 | pub(crate) fn check_no_diagnostics(ra_fixture: &str) { |
381 | let (analysis, files) = fixture::files(ra_fixture); | 288 | let (analysis, files) = fixture::files(ra_fixture); |
382 | let diagnostics = files | 289 | let diagnostics = files |
383 | .into_iter() | 290 | .into_iter() |
@@ -778,104 +685,6 @@ mod a { | |||
778 | } | 685 | } |
779 | 686 | ||
780 | #[test] | 687 | #[test] |
781 | fn test_check_expr_field_shorthand() { | ||
782 | check_no_diagnostics( | ||
783 | r#" | ||
784 | struct A { a: &'static str } | ||
785 | fn main() { A { a: "hello" } } | ||
786 | "#, | ||
787 | ); | ||
788 | check_no_diagnostics( | ||
789 | r#" | ||
790 | struct A(usize); | ||
791 | fn main() { A { 0: 0 } } | ||
792 | "#, | ||
793 | ); | ||
794 | |||
795 | check_fix( | ||
796 | r#" | ||
797 | struct A { a: &'static str } | ||
798 | fn main() { | ||
799 | let a = "haha"; | ||
800 | A { a<|>: a } | ||
801 | } | ||
802 | "#, | ||
803 | r#" | ||
804 | struct A { a: &'static str } | ||
805 | fn main() { | ||
806 | let a = "haha"; | ||
807 | A { a } | ||
808 | } | ||
809 | "#, | ||
810 | ); | ||
811 | |||
812 | check_fix( | ||
813 | r#" | ||
814 | struct A { a: &'static str, b: &'static str } | ||
815 | fn main() { | ||
816 | let a = "haha"; | ||
817 | let b = "bb"; | ||
818 | A { a<|>: a, b } | ||
819 | } | ||
820 | "#, | ||
821 | r#" | ||
822 | struct A { a: &'static str, b: &'static str } | ||
823 | fn main() { | ||
824 | let a = "haha"; | ||
825 | let b = "bb"; | ||
826 | A { a, b } | ||
827 | } | ||
828 | "#, | ||
829 | ); | ||
830 | } | ||
831 | |||
832 | #[test] | ||
833 | fn test_check_pat_field_shorthand() { | ||
834 | check_no_diagnostics( | ||
835 | r#" | ||
836 | struct A { a: &'static str } | ||
837 | fn f(a: A) { let A { a: hello } = a; } | ||
838 | "#, | ||
839 | ); | ||
840 | check_no_diagnostics( | ||
841 | r#" | ||
842 | struct A(usize); | ||
843 | fn f(a: A) { let A { 0: 0 } = a; } | ||
844 | "#, | ||
845 | ); | ||
846 | |||
847 | check_fix( | ||
848 | r#" | ||
849 | struct A { a: &'static str } | ||
850 | fn f(a: A) { | ||
851 | let A { a<|>: a } = a; | ||
852 | } | ||
853 | "#, | ||
854 | r#" | ||
855 | struct A { a: &'static str } | ||
856 | fn f(a: A) { | ||
857 | let A { a } = a; | ||
858 | } | ||
859 | "#, | ||
860 | ); | ||
861 | |||
862 | check_fix( | ||
863 | r#" | ||
864 | struct A { a: &'static str, b: &'static str } | ||
865 | fn f(a: A) { | ||
866 | let A { a<|>: a, b } = a; | ||
867 | } | ||
868 | "#, | ||
869 | r#" | ||
870 | struct A { a: &'static str, b: &'static str } | ||
871 | fn f(a: A) { | ||
872 | let A { a, b } = a; | ||
873 | } | ||
874 | "#, | ||
875 | ); | ||
876 | } | ||
877 | |||
878 | #[test] | ||
879 | fn test_add_field_from_usage() { | 688 | fn test_add_field_from_usage() { |
880 | check_fix( | 689 | check_fix( |
881 | r" | 690 | r" |