diff options
Diffstat (limited to 'crates/ide/src/diagnostics.rs')
-rw-r--r-- | crates/ide/src/diagnostics.rs | 141 |
1 files changed, 139 insertions, 2 deletions
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index f5d627b6e..b30cdb6ed 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -96,6 +96,9 @@ pub(crate) fn diagnostics( | |||
96 | .on::<hir::diagnostics::NoSuchField, _>(|d| { | 96 | .on::<hir::diagnostics::NoSuchField, _>(|d| { |
97 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); | 97 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); |
98 | }) | 98 | }) |
99 | .on::<hir::diagnostics::IncorrectCase, _>(|d| { | ||
100 | res.borrow_mut().push(warning_with_fix(d, &sema)); | ||
101 | }) | ||
99 | // Only collect experimental diagnostics when they're enabled. | 102 | // Only collect experimental diagnostics when they're enabled. |
100 | .filter(|diag| !(diag.is_experimental() && config.disable_experimental)) | 103 | .filter(|diag| !(diag.is_experimental() && config.disable_experimental)) |
101 | .filter(|diag| !config.disabled.contains(diag.code().as_str())); | 104 | .filter(|diag| !config.disabled.contains(diag.code().as_str())); |
@@ -130,6 +133,15 @@ fn diagnostic_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabas | |||
130 | } | 133 | } |
131 | } | 134 | } |
132 | 135 | ||
136 | fn warning_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { | ||
137 | Diagnostic { | ||
138 | range: sema.diagnostics_display_range(d).range, | ||
139 | message: d.message(), | ||
140 | severity: Severity::WeakWarning, | ||
141 | fix: d.fix(&sema), | ||
142 | } | ||
143 | } | ||
144 | |||
133 | fn check_unnecessary_braces_in_use_statement( | 145 | fn check_unnecessary_braces_in_use_statement( |
134 | acc: &mut Vec<Diagnostic>, | 146 | acc: &mut Vec<Diagnostic>, |
135 | file_id: FileId, | 147 | file_id: FileId, |
@@ -245,8 +257,37 @@ mod tests { | |||
245 | 257 | ||
246 | assert_eq_text!(&after, &actual); | 258 | assert_eq_text!(&after, &actual); |
247 | assert!( | 259 | assert!( |
248 | fix.fix_trigger_range.start() <= file_position.offset | 260 | fix.fix_trigger_range.contains_inclusive(file_position.offset), |
249 | && fix.fix_trigger_range.end() >= file_position.offset, | 261 | "diagnostic fix range {:?} does not touch cursor position {:?}", |
262 | fix.fix_trigger_range, | ||
263 | file_position.offset | ||
264 | ); | ||
265 | } | ||
266 | |||
267 | /// Similar to `check_fix`, but applies all the available fixes. | ||
268 | fn check_fixes(ra_fixture_before: &str, ra_fixture_after: &str) { | ||
269 | let after = trim_indent(ra_fixture_after); | ||
270 | |||
271 | let (analysis, file_position) = fixture::position(ra_fixture_before); | ||
272 | let diagnostic = analysis | ||
273 | .diagnostics(&DiagnosticsConfig::default(), file_position.file_id) | ||
274 | .unwrap() | ||
275 | .pop() | ||
276 | .unwrap(); | ||
277 | let fix = diagnostic.fix.unwrap(); | ||
278 | let target_file_contents = analysis.file_text(file_position.file_id).unwrap(); | ||
279 | let actual = { | ||
280 | let mut actual = target_file_contents.to_string(); | ||
281 | // Go from the last one to the first one, so that ranges won't be affected by previous edits. | ||
282 | for edit in fix.source_change.source_file_edits.iter().rev() { | ||
283 | edit.edit.apply(&mut actual); | ||
284 | } | ||
285 | actual | ||
286 | }; | ||
287 | |||
288 | assert_eq_text!(&after, &actual); | ||
289 | assert!( | ||
290 | fix.fix_trigger_range.contains_inclusive(file_position.offset), | ||
250 | "diagnostic fix range {:?} does not touch cursor position {:?}", | 291 | "diagnostic fix range {:?} does not touch cursor position {:?}", |
251 | fix.fix_trigger_range, | 292 | fix.fix_trigger_range, |
252 | file_position.offset | 293 | file_position.offset |
@@ -790,4 +831,100 @@ struct Foo { | |||
790 | let diagnostics = analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap(); | 831 | let diagnostics = analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap(); |
791 | assert!(!diagnostics.is_empty()); | 832 | assert!(!diagnostics.is_empty()); |
792 | } | 833 | } |
834 | |||
835 | #[test] | ||
836 | fn test_rename_incorrect_case() { | ||
837 | check_fixes( | ||
838 | r#" | ||
839 | pub struct test_struct<|> { one: i32 } | ||
840 | |||
841 | pub fn some_fn(val: test_struct) -> test_struct { | ||
842 | test_struct { one: val.one + 1 } | ||
843 | } | ||
844 | "#, | ||
845 | r#" | ||
846 | pub struct TestStruct { one: i32 } | ||
847 | |||
848 | pub fn some_fn(val: TestStruct) -> TestStruct { | ||
849 | TestStruct { one: val.one + 1 } | ||
850 | } | ||
851 | "#, | ||
852 | ); | ||
853 | |||
854 | check_fixes( | ||
855 | r#" | ||
856 | pub fn some_fn(NonSnakeCase<|>: u8) -> u8 { | ||
857 | NonSnakeCase | ||
858 | } | ||
859 | "#, | ||
860 | r#" | ||
861 | pub fn some_fn(non_snake_case: u8) -> u8 { | ||
862 | non_snake_case | ||
863 | } | ||
864 | "#, | ||
865 | ); | ||
866 | |||
867 | check_fixes( | ||
868 | r#" | ||
869 | pub fn SomeFn<|>(val: u8) -> u8 { | ||
870 | if val != 0 { SomeFn(val - 1) } else { val } | ||
871 | } | ||
872 | "#, | ||
873 | r#" | ||
874 | pub fn some_fn(val: u8) -> u8 { | ||
875 | if val != 0 { some_fn(val - 1) } else { val } | ||
876 | } | ||
877 | "#, | ||
878 | ); | ||
879 | |||
880 | check_fixes( | ||
881 | r#" | ||
882 | fn some_fn() { | ||
883 | let whatAWeird_Formatting<|> = 10; | ||
884 | another_func(whatAWeird_Formatting); | ||
885 | } | ||
886 | "#, | ||
887 | r#" | ||
888 | fn some_fn() { | ||
889 | let what_a_weird_formatting = 10; | ||
890 | another_func(what_a_weird_formatting); | ||
891 | } | ||
892 | "#, | ||
893 | ); | ||
894 | } | ||
895 | |||
896 | #[test] | ||
897 | fn test_uppercase_const_no_diagnostics() { | ||
898 | check_no_diagnostics( | ||
899 | r#" | ||
900 | fn foo() { | ||
901 | const ANOTHER_ITEM<|>: &str = "some_item"; | ||
902 | } | ||
903 | "#, | ||
904 | ); | ||
905 | } | ||
906 | |||
907 | #[test] | ||
908 | fn test_rename_incorrect_case_struct_method() { | ||
909 | check_fixes( | ||
910 | r#" | ||
911 | pub struct TestStruct; | ||
912 | |||
913 | impl TestStruct { | ||
914 | pub fn SomeFn<|>() -> TestStruct { | ||
915 | TestStruct | ||
916 | } | ||
917 | } | ||
918 | "#, | ||
919 | r#" | ||
920 | pub struct TestStruct; | ||
921 | |||
922 | impl TestStruct { | ||
923 | pub fn some_fn() -> TestStruct { | ||
924 | TestStruct | ||
925 | } | ||
926 | } | ||
927 | "#, | ||
928 | ); | ||
929 | } | ||
793 | } | 930 | } |