aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/diagnostics.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src/diagnostics.rs')
-rw-r--r--crates/ide/src/diagnostics.rs191
1 files changed, 7 insertions, 184 deletions
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index 4c92d0cf4..814e64ae4 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -9,8 +9,11 @@ mod inactive_code;
9mod macro_error; 9mod macro_error;
10mod mismatched_arg_count; 10mod mismatched_arg_count;
11mod missing_fields; 11mod missing_fields;
12mod missing_ok_or_some_in_tail_expr;
12mod missing_unsafe; 13mod missing_unsafe;
13mod no_such_field; 14mod no_such_field;
15mod remove_this_semicolon;
16mod replace_filter_map_next_with_find_map;
14mod unimplemented_builtin_macro; 17mod unimplemented_builtin_macro;
15mod unresolved_extern_crate; 18mod unresolved_extern_crate;
16mod unresolved_import; 19mod unresolved_import;
@@ -162,18 +165,9 @@ pub(crate) fn diagnostics(
162 } 165 }
163 let res = RefCell::new(res); 166 let res = RefCell::new(res);
164 let sink_builder = DiagnosticSinkBuilder::new() 167 let sink_builder = DiagnosticSinkBuilder::new()
165 .on::<hir::diagnostics::MissingOkOrSomeInTailExpr, _>(|d| {
166 res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve));
167 })
168 .on::<hir::diagnostics::RemoveThisSemicolon, _>(|d| {
169 res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve));
170 })
171 .on::<hir::diagnostics::IncorrectCase, _>(|d| { 168 .on::<hir::diagnostics::IncorrectCase, _>(|d| {
172 res.borrow_mut().push(warning_with_fix(d, &sema, resolve)); 169 res.borrow_mut().push(warning_with_fix(d, &sema, resolve));
173 }) 170 })
174 .on::<hir::diagnostics::ReplaceFilterMapNextWithFindMap, _>(|d| {
175 res.borrow_mut().push(warning_with_fix(d, &sema, resolve));
176 })
177 .on::<UnlinkedFile, _>(|d| { 171 .on::<UnlinkedFile, _>(|d| {
178 // Limit diagnostic to the first few characters in the file. This matches how VS Code 172 // Limit diagnostic to the first few characters in the file. This matches how VS Code
179 // renders it with the full span, but on other editors, and is less invasive. 173 // renders it with the full span, but on other editors, and is less invasive.
@@ -223,10 +217,13 @@ pub(crate) fn diagnostics(
223 let d = match diag { 217 let d = match diag {
224 AnyDiagnostic::BreakOutsideOfLoop(d) => break_outside_of_loop::break_outside_of_loop(&ctx, &d), 218 AnyDiagnostic::BreakOutsideOfLoop(d) => break_outside_of_loop::break_outside_of_loop(&ctx, &d),
225 AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d), 219 AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d),
220 AnyDiagnostic::MismatchedArgCount(d) => mismatched_arg_count::mismatched_arg_count(&ctx, &d),
226 AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d), 221 AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d),
222 AnyDiagnostic::MissingOkOrSomeInTailExpr(d) => missing_ok_or_some_in_tail_expr::missing_ok_or_some_in_tail_expr(&ctx, &d),
227 AnyDiagnostic::MissingUnsafe(d) => missing_unsafe::missing_unsafe(&ctx, &d), 223 AnyDiagnostic::MissingUnsafe(d) => missing_unsafe::missing_unsafe(&ctx, &d),
228 AnyDiagnostic::MismatchedArgCount(d) => mismatched_arg_count::mismatched_arg_count(&ctx, &d),
229 AnyDiagnostic::NoSuchField(d) => no_such_field::no_such_field(&ctx, &d), 224 AnyDiagnostic::NoSuchField(d) => no_such_field::no_such_field(&ctx, &d),
225 AnyDiagnostic::RemoveThisSemicolon(d) => remove_this_semicolon::remove_this_semicolon(&ctx, &d),
226 AnyDiagnostic::ReplaceFilterMapNextWithFindMap(d) => replace_filter_map_next_with_find_map::replace_filter_map_next_with_find_map(&ctx, &d),
230 AnyDiagnostic::UnimplementedBuiltinMacro(d) => unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d), 227 AnyDiagnostic::UnimplementedBuiltinMacro(d) => unimplemented_builtin_macro::unimplemented_builtin_macro(&ctx, &d),
231 AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d), 228 AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d),
232 AnyDiagnostic::UnresolvedImport(d) => unresolved_import::unresolved_import(&ctx, &d), 229 AnyDiagnostic::UnresolvedImport(d) => unresolved_import::unresolved_import(&ctx, &d),
@@ -253,16 +250,6 @@ pub(crate) fn diagnostics(
253 res 250 res
254} 251}
255 252
256fn diagnostic_with_fix<D: DiagnosticWithFixes>(
257 d: &D,
258 sema: &Semantics<RootDatabase>,
259 resolve: &AssistResolveStrategy,
260) -> Diagnostic {
261 Diagnostic::error(sema.diagnostics_display_range(d.display_source()).range, d.message())
262 .with_fixes(d.fixes(sema, resolve))
263 .with_code(Some(d.code()))
264}
265
266fn warning_with_fix<D: DiagnosticWithFixes>( 253fn warning_with_fix<D: DiagnosticWithFixes>(
267 d: &D, 254 d: &D,
268 sema: &Semantics<RootDatabase>, 255 sema: &Semantics<RootDatabase>,
@@ -449,39 +436,6 @@ mod tests {
449 } 436 }
450 437
451 #[test] 438 #[test]
452 fn range_mapping_out_of_macros() {
453 // FIXME: this is very wrong, but somewhat tricky to fix.
454 check_fix(
455 r#"
456fn some() {}
457fn items() {}
458fn here() {}
459
460macro_rules! id { ($($tt:tt)*) => { $($tt)*}; }
461
462fn main() {
463 let _x = id![Foo { a: $042 }];
464}
465
466pub struct Foo { pub a: i32, pub b: i32 }
467"#,
468 r#"
469fn some(, b: () ) {}
470fn items() {}
471fn here() {}
472
473macro_rules! id { ($($tt:tt)*) => { $($tt)*}; }
474
475fn main() {
476 let _x = id![Foo { a: 42 }];
477}
478
479pub struct Foo { pub a: i32, pub b: i32 }
480"#,
481 );
482 }
483
484 #[test]
485 fn test_check_unnecessary_braces_in_use_statement() { 439 fn test_check_unnecessary_braces_in_use_statement() {
486 check_diagnostics( 440 check_diagnostics(
487 r#" 441 r#"
@@ -717,137 +671,6 @@ mod foo;
717 ); 671 );
718 } 672 }
719 673
720 // Register the required standard library types to make the tests work
721 fn add_filter_map_with_find_next_boilerplate(body: &str) -> String {
722 let prefix = r#"
723 //- /main.rs crate:main deps:core
724 use core::iter::Iterator;
725 use core::option::Option::{self, Some, None};
726 "#;
727 let suffix = r#"
728 //- /core/lib.rs crate:core
729 pub mod option {
730 pub enum Option<T> { Some(T), None }
731 }
732 pub mod iter {
733 pub trait Iterator {
734 type Item;
735 fn filter_map<B, F>(self, f: F) -> FilterMap where F: FnMut(Self::Item) -> Option<B> { FilterMap }
736 fn next(&mut self) -> Option<Self::Item>;
737 }
738 pub struct FilterMap {}
739 impl Iterator for FilterMap {
740 type Item = i32;
741 fn next(&mut self) -> i32 { 7 }
742 }
743 }
744 "#;
745 format!("{}{}{}", prefix, body, suffix)
746 }
747
748 #[test]
749 fn replace_filter_map_next_with_find_map2() {
750 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
751 r#"
752 fn foo() {
753 let m = [1, 2, 3].iter().filter_map(|x| if *x == 2 { Some (4) } else { None }).next();
754 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ replace filter_map(..).next() with find_map(..)
755 }
756 "#,
757 ));
758 }
759
760 #[test]
761 fn replace_filter_map_next_with_find_map_no_diagnostic_without_next() {
762 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
763 r#"
764 fn foo() {
765 let m = [1, 2, 3]
766 .iter()
767 .filter_map(|x| if *x == 2 { Some (4) } else { None })
768 .len();
769 }
770 "#,
771 ));
772 }
773
774 #[test]
775 fn replace_filter_map_next_with_find_map_no_diagnostic_with_intervening_methods() {
776 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
777 r#"
778 fn foo() {
779 let m = [1, 2, 3]
780 .iter()
781 .filter_map(|x| if *x == 2 { Some (4) } else { None })
782 .map(|x| x + 2)
783 .len();
784 }
785 "#,
786 ));
787 }
788
789 #[test]
790 fn replace_filter_map_next_with_find_map_no_diagnostic_if_not_in_chain() {
791 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
792 r#"
793 fn foo() {
794 let m = [1, 2, 3]
795 .iter()
796 .filter_map(|x| if *x == 2 { Some (4) } else { None });
797 let n = m.next();
798 }
799 "#,
800 ));
801 }
802
803 #[test]
804 fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
805 check_diagnostics(
806 r"
807struct S { foo: i32, bar: () }
808fn baz(s: S) -> i32 {
809 match s {
810 S { foo, .. } => foo,
811 }
812}
813",
814 )
815 }
816
817 #[test]
818 fn missing_record_pat_field_box() {
819 check_diagnostics(
820 r"
821struct S { s: Box<u32> }
822fn x(a: S) {
823 let S { box s } = a;
824}
825",
826 )
827 }
828
829 #[test]
830 fn missing_record_pat_field_ref() {
831 check_diagnostics(
832 r"
833struct S { s: u32 }
834fn x(a: S) {
835 let S { ref s } = a;
836}
837",
838 )
839 }
840
841 #[test]
842 fn missing_semicolon() {
843 check_diagnostics(
844 r#"
845 fn test() -> i32 { 123; }
846 //^^^ Remove this semicolon
847 "#,
848 );
849 }
850
851 #[test] 674 #[test]
852 fn import_extern_crate_clash_with_inner_item() { 675 fn import_extern_crate_clash_with_inner_item() {
853 // This is more of a resolver test, but doesn't really work with the hir_def testsuite. 676 // This is more of a resolver test, but doesn't really work with the hir_def testsuite.