]> git.lizzy.rs Git - rust.git/blob - crates/ide/src/diagnostics.rs
Merge #9251
[rust.git] / crates / ide / src / diagnostics.rs
1 //! Collects diagnostics & fixits  for a single file.
2 //!
3 //! The tricky bit here is that diagnostics are produced by hir in terms of
4 //! macro-expanded files, but we need to present them to the users in terms of
5 //! original files. So we need to map the ranges.
6
7 mod unresolved_module;
8 mod unresolved_extern_crate;
9 mod unresolved_import;
10 mod unresolved_macro_call;
11 mod unresolved_proc_macro;
12 mod macro_error;
13 mod inactive_code;
14 mod missing_fields;
15
16 mod fixes;
17 mod field_shorthand;
18 mod unlinked_file;
19
20 use std::cell::RefCell;
21
22 use hir::{
23     diagnostics::{AnyDiagnostic, Diagnostic as _, DiagnosticCode, DiagnosticSinkBuilder},
24     Semantics,
25 };
26 use ide_assists::AssistResolveStrategy;
27 use ide_db::{base_db::SourceDatabase, RootDatabase};
28 use itertools::Itertools;
29 use rustc_hash::FxHashSet;
30 use syntax::{
31     ast::{self, AstNode},
32     SyntaxNode, SyntaxNodePtr, TextRange, TextSize,
33 };
34 use text_edit::TextEdit;
35 use unlinked_file::UnlinkedFile;
36
37 use crate::{Assist, AssistId, AssistKind, FileId, Label, SourceChange};
38
39 use self::fixes::DiagnosticWithFixes;
40
41 #[derive(Debug)]
42 pub struct Diagnostic {
43     // pub name: Option<String>,
44     pub message: String,
45     pub range: TextRange,
46     pub severity: Severity,
47     pub fixes: Option<Vec<Assist>>,
48     pub unused: bool,
49     pub code: Option<DiagnosticCode>,
50     pub experimental: bool,
51 }
52
53 impl Diagnostic {
54     fn new(code: &'static str, message: impl Into<String>, range: TextRange) -> Diagnostic {
55         let message = message.into();
56         let code = Some(DiagnosticCode(code));
57         Self {
58             message,
59             range,
60             severity: Severity::Error,
61             fixes: None,
62             unused: false,
63             code,
64             experimental: false,
65         }
66     }
67
68     fn experimental(mut self) -> Diagnostic {
69         self.experimental = true;
70         self
71     }
72
73     fn severity(mut self, severity: Severity) -> Diagnostic {
74         self.severity = severity;
75         self
76     }
77
78     fn error(range: TextRange, message: String) -> Self {
79         Self {
80             message,
81             range,
82             severity: Severity::Error,
83             fixes: None,
84             unused: false,
85             code: None,
86             experimental: false,
87         }
88     }
89
90     fn hint(range: TextRange, message: String) -> Self {
91         Self {
92             message,
93             range,
94             severity: Severity::WeakWarning,
95             fixes: None,
96             unused: false,
97             code: None,
98             experimental: false,
99         }
100     }
101
102     fn with_fixes(self, fixes: Option<Vec<Assist>>) -> Self {
103         Self { fixes, ..self }
104     }
105
106     fn with_unused(self, unused: bool) -> Self {
107         Self { unused, ..self }
108     }
109
110     fn with_code(self, code: Option<DiagnosticCode>) -> Self {
111         Self { code, ..self }
112     }
113 }
114
115 #[derive(Debug, Copy, Clone)]
116 pub enum Severity {
117     Error,
118     WeakWarning,
119 }
120
121 #[derive(Default, Debug, Clone)]
122 pub struct DiagnosticsConfig {
123     pub disable_experimental: bool,
124     pub disabled: FxHashSet<String>,
125 }
126
127 struct DiagnosticsContext<'a> {
128     config: &'a DiagnosticsConfig,
129     sema: Semantics<'a, RootDatabase>,
130     #[allow(unused)]
131     resolve: &'a AssistResolveStrategy,
132 }
133
134 pub(crate) fn diagnostics(
135     db: &RootDatabase,
136     config: &DiagnosticsConfig,
137     resolve: &AssistResolveStrategy,
138     file_id: FileId,
139 ) -> Vec<Diagnostic> {
140     let _p = profile::span("diagnostics");
141     let sema = Semantics::new(db);
142     let parse = db.parse(file_id);
143     let mut res = Vec::new();
144
145     // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily.
146     res.extend(
147         parse
148             .errors()
149             .iter()
150             .take(128)
151             .map(|err| Diagnostic::error(err.range(), format!("Syntax Error: {}", err))),
152     );
153
154     for node in parse.tree().syntax().descendants() {
155         check_unnecessary_braces_in_use_statement(&mut res, file_id, &node);
156         field_shorthand::check(&mut res, file_id, &node);
157     }
158     let res = RefCell::new(res);
159     let sink_builder = DiagnosticSinkBuilder::new()
160         .on::<hir::diagnostics::MissingOkOrSomeInTailExpr, _>(|d| {
161             res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve));
162         })
163         .on::<hir::diagnostics::NoSuchField, _>(|d| {
164             res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve));
165         })
166         .on::<hir::diagnostics::RemoveThisSemicolon, _>(|d| {
167             res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve));
168         })
169         .on::<hir::diagnostics::IncorrectCase, _>(|d| {
170             res.borrow_mut().push(warning_with_fix(d, &sema, resolve));
171         })
172         .on::<hir::diagnostics::ReplaceFilterMapNextWithFindMap, _>(|d| {
173             res.borrow_mut().push(warning_with_fix(d, &sema, resolve));
174         })
175         .on::<UnlinkedFile, _>(|d| {
176             // Limit diagnostic to the first few characters in the file. This matches how VS Code
177             // renders it with the full span, but on other editors, and is less invasive.
178             let range = sema.diagnostics_display_range(d.display_source()).range;
179             let range = range.intersect(TextRange::up_to(TextSize::of("..."))).unwrap_or(range);
180
181             // Override severity and mark as unused.
182             res.borrow_mut().push(
183                 Diagnostic::hint(range, d.message())
184                     .with_fixes(d.fixes(&sema, resolve))
185                     .with_code(Some(d.code())),
186             );
187         })
188         .on::<hir::diagnostics::UnimplementedBuiltinMacro, _>(|d| {
189             let display_range = sema.diagnostics_display_range(d.display_source()).range;
190             res.borrow_mut()
191                 .push(Diagnostic::hint(display_range, d.message()).with_code(Some(d.code())));
192         })
193         // Only collect experimental diagnostics when they're enabled.
194         .filter(|diag| !(diag.is_experimental() && config.disable_experimental))
195         .filter(|diag| !config.disabled.contains(diag.code().as_str()));
196
197     // Finalize the `DiagnosticSink` building process.
198     let mut sink = sink_builder
199         // Diagnostics not handled above get no fix and default treatment.
200         .build(|d| {
201             res.borrow_mut().push(
202                 Diagnostic::error(
203                     sema.diagnostics_display_range(d.display_source()).range,
204                     d.message(),
205                 )
206                 .with_code(Some(d.code())),
207             );
208         });
209
210     let mut diags = Vec::new();
211     let internal_diagnostics = cfg!(test);
212     match sema.to_module_def(file_id) {
213         Some(m) => diags = m.diagnostics(db, &mut sink, internal_diagnostics),
214         None => {
215             sink.push(UnlinkedFile { file_id, node: SyntaxNodePtr::new(parse.tree().syntax()) });
216         }
217     }
218
219     drop(sink);
220
221     let mut res = res.into_inner();
222
223     let ctx = DiagnosticsContext { config, sema, resolve };
224     for diag in diags {
225         #[rustfmt::skip]
226         let d = match diag {
227             AnyDiagnostic::UnresolvedModule(d) => unresolved_module::unresolved_module(&ctx, &d),
228             AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d),
229             AnyDiagnostic::UnresolvedImport(d) => unresolved_import::unresolved_import(&ctx, &d),
230             AnyDiagnostic::UnresolvedMacroCall(d) => unresolved_macro_call::unresolved_macro_call(&ctx, &d),
231             AnyDiagnostic::UnresolvedProcMacro(d) => unresolved_proc_macro::unresolved_proc_macro(&ctx, &d),
232             AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d),
233             AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d),
234
235             AnyDiagnostic::InactiveCode(d) => match inactive_code::inactive_code(&ctx, &d) {
236                 Some(it) => it,
237                 None => continue,
238             }
239         };
240         if let Some(code) = d.code {
241             if ctx.config.disabled.contains(code.as_str()) {
242                 continue;
243             }
244         }
245         if ctx.config.disable_experimental && d.experimental {
246             continue;
247         }
248         res.push(d)
249     }
250
251     res
252 }
253
254 fn diagnostic_with_fix<D: DiagnosticWithFixes>(
255     d: &D,
256     sema: &Semantics<RootDatabase>,
257     resolve: &AssistResolveStrategy,
258 ) -> Diagnostic {
259     Diagnostic::error(sema.diagnostics_display_range(d.display_source()).range, d.message())
260         .with_fixes(d.fixes(sema, resolve))
261         .with_code(Some(d.code()))
262 }
263
264 fn warning_with_fix<D: DiagnosticWithFixes>(
265     d: &D,
266     sema: &Semantics<RootDatabase>,
267     resolve: &AssistResolveStrategy,
268 ) -> Diagnostic {
269     Diagnostic::hint(sema.diagnostics_display_range(d.display_source()).range, d.message())
270         .with_fixes(d.fixes(sema, resolve))
271         .with_code(Some(d.code()))
272 }
273
274 fn check_unnecessary_braces_in_use_statement(
275     acc: &mut Vec<Diagnostic>,
276     file_id: FileId,
277     node: &SyntaxNode,
278 ) -> Option<()> {
279     let use_tree_list = ast::UseTreeList::cast(node.clone())?;
280     if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() {
281         // If there is a comment inside the bracketed `use`,
282         // assume it is a commented out module path and don't show diagnostic.
283         if use_tree_list.has_inner_comment() {
284             return Some(());
285         }
286
287         let use_range = use_tree_list.syntax().text_range();
288         let edit =
289             text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(&single_use_tree)
290                 .unwrap_or_else(|| {
291                     let to_replace = single_use_tree.syntax().text().to_string();
292                     let mut edit_builder = TextEdit::builder();
293                     edit_builder.delete(use_range);
294                     edit_builder.insert(use_range.start(), to_replace);
295                     edit_builder.finish()
296                 });
297
298         acc.push(
299             Diagnostic::hint(use_range, "Unnecessary braces in use statement".to_string())
300                 .with_fixes(Some(vec![fix(
301                     "remove_braces",
302                     "Remove unnecessary braces",
303                     SourceChange::from_text_edit(file_id, edit),
304                     use_range,
305                 )])),
306         );
307     }
308
309     Some(())
310 }
311
312 fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(
313     single_use_tree: &ast::UseTree,
314 ) -> Option<TextEdit> {
315     let use_tree_list_node = single_use_tree.syntax().parent()?;
316     if single_use_tree.path()?.segment()?.self_token().is_some() {
317         let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start();
318         let end = use_tree_list_node.text_range().end();
319         return Some(TextEdit::delete(TextRange::new(start, end)));
320     }
321     None
322 }
323
324 fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist {
325     let mut res = unresolved_fix(id, label, target);
326     res.source_change = Some(source_change);
327     res
328 }
329
330 fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist {
331     assert!(!id.contains(' '));
332     Assist {
333         id: AssistId(id, AssistKind::QuickFix),
334         label: Label::new(label),
335         group: None,
336         target,
337         source_change: None,
338     }
339 }
340
341 #[cfg(test)]
342 mod tests {
343     use expect_test::Expect;
344     use ide_assists::AssistResolveStrategy;
345     use stdx::trim_indent;
346     use test_utils::{assert_eq_text, extract_annotations};
347
348     use crate::{fixture, DiagnosticsConfig};
349
350     /// Takes a multi-file input fixture with annotated cursor positions,
351     /// and checks that:
352     ///  * a diagnostic is produced
353     ///  * the first diagnostic fix trigger range touches the input cursor position
354     ///  * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied
355     #[track_caller]
356     pub(crate) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) {
357         check_nth_fix(0, ra_fixture_before, ra_fixture_after);
358     }
359     /// Takes a multi-file input fixture with annotated cursor positions,
360     /// and checks that:
361     ///  * a diagnostic is produced
362     ///  * every diagnostic fixes trigger range touches the input cursor position
363     ///  * that the contents of the file containing the cursor match `after` after each diagnostic fix is applied
364     pub(crate) fn check_fixes(ra_fixture_before: &str, ra_fixtures_after: Vec<&str>) {
365         for (i, ra_fixture_after) in ra_fixtures_after.iter().enumerate() {
366             check_nth_fix(i, ra_fixture_before, ra_fixture_after)
367         }
368     }
369
370     #[track_caller]
371     fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) {
372         let after = trim_indent(ra_fixture_after);
373
374         let (analysis, file_position) = fixture::position(ra_fixture_before);
375         let diagnostic = analysis
376             .diagnostics(
377                 &DiagnosticsConfig::default(),
378                 AssistResolveStrategy::All,
379                 file_position.file_id,
380             )
381             .unwrap()
382             .pop()
383             .unwrap();
384         let fix = &diagnostic.fixes.unwrap()[nth];
385         let actual = {
386             let source_change = fix.source_change.as_ref().unwrap();
387             let file_id = *source_change.source_file_edits.keys().next().unwrap();
388             let mut actual = analysis.file_text(file_id).unwrap().to_string();
389
390             for edit in source_change.source_file_edits.values() {
391                 edit.apply(&mut actual);
392             }
393             actual
394         };
395
396         assert_eq_text!(&after, &actual);
397         assert!(
398             fix.target.contains_inclusive(file_position.offset),
399             "diagnostic fix range {:?} does not touch cursor position {:?}",
400             fix.target,
401             file_position.offset
402         );
403     }
404     /// Checks that there's a diagnostic *without* fix at `$0`.
405     fn check_no_fix(ra_fixture: &str) {
406         let (analysis, file_position) = fixture::position(ra_fixture);
407         let diagnostic = analysis
408             .diagnostics(
409                 &DiagnosticsConfig::default(),
410                 AssistResolveStrategy::All,
411                 file_position.file_id,
412             )
413             .unwrap()
414             .pop()
415             .unwrap();
416         assert!(diagnostic.fixes.is_none(), "got a fix when none was expected: {:?}", diagnostic);
417     }
418
419     pub(crate) fn check_expect(ra_fixture: &str, expect: Expect) {
420         let (analysis, file_id) = fixture::file(ra_fixture);
421         let diagnostics = analysis
422             .diagnostics(&DiagnosticsConfig::default(), AssistResolveStrategy::All, file_id)
423             .unwrap();
424         expect.assert_debug_eq(&diagnostics)
425     }
426
427     #[track_caller]
428     pub(crate) fn check_diagnostics(ra_fixture: &str) {
429         let mut config = DiagnosticsConfig::default();
430         config.disabled.insert("inactive-code".to_string());
431         check_diagnostics_with_config(config, ra_fixture)
432     }
433
434     #[track_caller]
435     pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixture: &str) {
436         let (analysis, files) = fixture::files(ra_fixture);
437         for file_id in files {
438             let diagnostics =
439                 analysis.diagnostics(&config, AssistResolveStrategy::All, file_id).unwrap();
440
441             let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
442             let mut actual =
443                 diagnostics.into_iter().map(|d| (d.range, d.message)).collect::<Vec<_>>();
444             actual.sort_by_key(|(range, _)| range.start());
445             assert_eq!(expected, actual);
446         }
447     }
448
449     #[test]
450     fn range_mapping_out_of_macros() {
451         // FIXME: this is very wrong, but somewhat tricky to fix.
452         check_fix(
453             r#"
454 fn some() {}
455 fn items() {}
456 fn here() {}
457
458 macro_rules! id { ($($tt:tt)*) => { $($tt)*}; }
459
460 fn main() {
461     let _x = id![Foo { a: $042 }];
462 }
463
464 pub struct Foo { pub a: i32, pub b: i32 }
465 "#,
466             r#"
467 fn some(, b: () ) {}
468 fn items() {}
469 fn here() {}
470
471 macro_rules! id { ($($tt:tt)*) => { $($tt)*}; }
472
473 fn main() {
474     let _x = id![Foo { a: 42 }];
475 }
476
477 pub struct Foo { pub a: i32, pub b: i32 }
478 "#,
479         );
480     }
481
482     #[test]
483     fn test_check_unnecessary_braces_in_use_statement() {
484         check_diagnostics(
485             r#"
486 use a;
487 use a::{c, d::e};
488
489 mod a {
490     mod c {}
491     mod d {
492         mod e {}
493     }
494 }
495 "#,
496         );
497         check_diagnostics(
498             r#"
499 use a;
500 use a::{
501     c,
502     // d::e
503 };
504
505 mod a {
506     mod c {}
507     mod d {
508         mod e {}
509     }
510 }
511 "#,
512         );
513         check_fix(
514             r"
515             mod b {}
516             use {$0b};
517             ",
518             r"
519             mod b {}
520             use b;
521             ",
522         );
523         check_fix(
524             r"
525             mod b {}
526             use {b$0};
527             ",
528             r"
529             mod b {}
530             use b;
531             ",
532         );
533         check_fix(
534             r"
535             mod a { mod c {} }
536             use a::{c$0};
537             ",
538             r"
539             mod a { mod c {} }
540             use a::c;
541             ",
542         );
543         check_fix(
544             r"
545             mod a {}
546             use a::{self$0};
547             ",
548             r"
549             mod a {}
550             use a;
551             ",
552         );
553         check_fix(
554             r"
555             mod a { mod c {} mod d { mod e {} } }
556             use a::{c, d::{e$0}};
557             ",
558             r"
559             mod a { mod c {} mod d { mod e {} } }
560             use a::{c, d::e};
561             ",
562         );
563     }
564
565     #[test]
566     fn test_disabled_diagnostics() {
567         let mut config = DiagnosticsConfig::default();
568         config.disabled.insert("unresolved-module".into());
569
570         let (analysis, file_id) = fixture::file(r#"mod foo;"#);
571
572         let diagnostics =
573             analysis.diagnostics(&config, AssistResolveStrategy::All, file_id).unwrap();
574         assert!(diagnostics.is_empty());
575
576         let diagnostics = analysis
577             .diagnostics(&DiagnosticsConfig::default(), AssistResolveStrategy::All, file_id)
578             .unwrap();
579         assert!(!diagnostics.is_empty());
580     }
581
582     #[test]
583     fn unlinked_file_prepend_first_item() {
584         cov_mark::check!(unlinked_file_prepend_before_first_item);
585         // Only tests the first one for `pub mod` since the rest are the same
586         check_fixes(
587             r#"
588 //- /main.rs
589 fn f() {}
590 //- /foo.rs
591 $0
592 "#,
593             vec![
594                 r#"
595 mod foo;
596
597 fn f() {}
598 "#,
599                 r#"
600 pub mod foo;
601
602 fn f() {}
603 "#,
604             ],
605         );
606     }
607
608     #[test]
609     fn unlinked_file_append_mod() {
610         cov_mark::check!(unlinked_file_append_to_existing_mods);
611         check_fix(
612             r#"
613 //- /main.rs
614 //! Comment on top
615
616 mod preexisting;
617
618 mod preexisting2;
619
620 struct S;
621
622 mod preexisting_bottom;)
623 //- /foo.rs
624 $0
625 "#,
626             r#"
627 //! Comment on top
628
629 mod preexisting;
630
631 mod preexisting2;
632 mod foo;
633
634 struct S;
635
636 mod preexisting_bottom;)
637 "#,
638         );
639     }
640
641     #[test]
642     fn unlinked_file_insert_in_empty_file() {
643         cov_mark::check!(unlinked_file_empty_file);
644         check_fix(
645             r#"
646 //- /main.rs
647 //- /foo.rs
648 $0
649 "#,
650             r#"
651 mod foo;
652 "#,
653         );
654     }
655
656     #[test]
657     fn unlinked_file_old_style_modrs() {
658         check_fix(
659             r#"
660 //- /main.rs
661 mod submod;
662 //- /submod/mod.rs
663 // in mod.rs
664 //- /submod/foo.rs
665 $0
666 "#,
667             r#"
668 // in mod.rs
669 mod foo;
670 "#,
671         );
672     }
673
674     #[test]
675     fn unlinked_file_new_style_mod() {
676         check_fix(
677             r#"
678 //- /main.rs
679 mod submod;
680 //- /submod.rs
681 //- /submod/foo.rs
682 $0
683 "#,
684             r#"
685 mod foo;
686 "#,
687         );
688     }
689
690     #[test]
691     fn unlinked_file_with_cfg_off() {
692         cov_mark::check!(unlinked_file_skip_fix_when_mod_already_exists);
693         check_no_fix(
694             r#"
695 //- /main.rs
696 #[cfg(never)]
697 mod foo;
698
699 //- /foo.rs
700 $0
701 "#,
702         );
703     }
704
705     #[test]
706     fn unlinked_file_with_cfg_on() {
707         check_diagnostics(
708             r#"
709 //- /main.rs
710 #[cfg(not(never))]
711 mod foo;
712
713 //- /foo.rs
714 "#,
715         );
716     }
717
718     #[test]
719     fn break_outside_of_loop() {
720         check_diagnostics(
721             r#"
722 fn foo() { break; }
723          //^^^^^ break outside of loop
724 "#,
725         );
726     }
727
728     #[test]
729     fn no_such_field_diagnostics() {
730         check_diagnostics(
731             r#"
732 struct S { foo: i32, bar: () }
733 impl S {
734     fn new() -> S {
735         S {
736       //^ Missing structure fields:
737       //|    - bar
738             foo: 92,
739             baz: 62,
740           //^^^^^^^ no such field
741         }
742     }
743 }
744 "#,
745         );
746     }
747     #[test]
748     fn no_such_field_with_feature_flag_diagnostics() {
749         check_diagnostics(
750             r#"
751 //- /lib.rs crate:foo cfg:feature=foo
752 struct MyStruct {
753     my_val: usize,
754     #[cfg(feature = "foo")]
755     bar: bool,
756 }
757
758 impl MyStruct {
759     #[cfg(feature = "foo")]
760     pub(crate) fn new(my_val: usize, bar: bool) -> Self {
761         Self { my_val, bar }
762     }
763     #[cfg(not(feature = "foo"))]
764     pub(crate) fn new(my_val: usize, _bar: bool) -> Self {
765         Self { my_val }
766     }
767 }
768 "#,
769         );
770     }
771
772     #[test]
773     fn no_such_field_enum_with_feature_flag_diagnostics() {
774         check_diagnostics(
775             r#"
776 //- /lib.rs crate:foo cfg:feature=foo
777 enum Foo {
778     #[cfg(not(feature = "foo"))]
779     Buz,
780     #[cfg(feature = "foo")]
781     Bar,
782     Baz
783 }
784
785 fn test_fn(f: Foo) {
786     match f {
787         Foo::Bar => {},
788         Foo::Baz => {},
789     }
790 }
791 "#,
792         );
793     }
794
795     #[test]
796     fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() {
797         check_diagnostics(
798             r#"
799 //- /lib.rs crate:foo cfg:feature=foo
800 struct S {
801     #[cfg(feature = "foo")]
802     foo: u32,
803     #[cfg(not(feature = "foo"))]
804     bar: u32,
805 }
806
807 impl S {
808     #[cfg(feature = "foo")]
809     fn new(foo: u32) -> Self {
810         Self { foo }
811     }
812     #[cfg(not(feature = "foo"))]
813     fn new(bar: u32) -> Self {
814         Self { bar }
815     }
816     fn new2(bar: u32) -> Self {
817         #[cfg(feature = "foo")]
818         { Self { foo: bar } }
819         #[cfg(not(feature = "foo"))]
820         { Self { bar } }
821     }
822     fn new2(val: u32) -> Self {
823         Self {
824             #[cfg(feature = "foo")]
825             foo: val,
826             #[cfg(not(feature = "foo"))]
827             bar: val,
828         }
829     }
830 }
831 "#,
832         );
833     }
834
835     #[test]
836     fn no_such_field_with_type_macro() {
837         check_diagnostics(
838             r#"
839 macro_rules! Type { () => { u32 }; }
840 struct Foo { bar: Type![] }
841
842 impl Foo {
843     fn new() -> Self {
844         Foo { bar: 0 }
845     }
846 }
847 "#,
848         );
849     }
850
851     #[test]
852     fn missing_unsafe_diagnostic_with_raw_ptr() {
853         check_diagnostics(
854             r#"
855 fn main() {
856     let x = &5 as *const usize;
857     unsafe { let y = *x; }
858     let z = *x;
859 }         //^^ This operation is unsafe and requires an unsafe function or block
860 "#,
861         )
862     }
863
864     #[test]
865     fn missing_unsafe_diagnostic_with_unsafe_call() {
866         check_diagnostics(
867             r#"
868 struct HasUnsafe;
869
870 impl HasUnsafe {
871     unsafe fn unsafe_fn(&self) {
872         let x = &5 as *const usize;
873         let y = *x;
874     }
875 }
876
877 unsafe fn unsafe_fn() {
878     let x = &5 as *const usize;
879     let y = *x;
880 }
881
882 fn main() {
883     unsafe_fn();
884   //^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
885     HasUnsafe.unsafe_fn();
886   //^^^^^^^^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
887     unsafe {
888         unsafe_fn();
889         HasUnsafe.unsafe_fn();
890     }
891 }
892 "#,
893         );
894     }
895
896     #[test]
897     fn missing_unsafe_diagnostic_with_static_mut() {
898         check_diagnostics(
899             r#"
900 struct Ty {
901     a: u8,
902 }
903
904 static mut STATIC_MUT: Ty = Ty { a: 0 };
905
906 fn main() {
907     let x = STATIC_MUT.a;
908           //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
909     unsafe {
910         let x = STATIC_MUT.a;
911     }
912 }
913 "#,
914         );
915     }
916
917     #[test]
918     fn no_missing_unsafe_diagnostic_with_safe_intrinsic() {
919         check_diagnostics(
920             r#"
921 extern "rust-intrinsic" {
922     pub fn bitreverse(x: u32) -> u32; // Safe intrinsic
923     pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic
924 }
925
926 fn main() {
927     let _ = bitreverse(12);
928     let _ = floorf32(12.0);
929           //^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
930 }
931 "#,
932         );
933     }
934
935     // Register the required standard library types to make the tests work
936     fn add_filter_map_with_find_next_boilerplate(body: &str) -> String {
937         let prefix = r#"
938         //- /main.rs crate:main deps:core
939         use core::iter::Iterator;
940         use core::option::Option::{self, Some, None};
941         "#;
942         let suffix = r#"
943         //- /core/lib.rs crate:core
944         pub mod option {
945             pub enum Option<T> { Some(T), None }
946         }
947         pub mod iter {
948             pub trait Iterator {
949                 type Item;
950                 fn filter_map<B, F>(self, f: F) -> FilterMap where F: FnMut(Self::Item) -> Option<B> { FilterMap }
951                 fn next(&mut self) -> Option<Self::Item>;
952             }
953             pub struct FilterMap {}
954             impl Iterator for FilterMap {
955                 type Item = i32;
956                 fn next(&mut self) -> i32 { 7 }
957             }
958         }
959         "#;
960         format!("{}{}{}", prefix, body, suffix)
961     }
962
963     #[test]
964     fn replace_filter_map_next_with_find_map2() {
965         check_diagnostics(&add_filter_map_with_find_next_boilerplate(
966             r#"
967             fn foo() {
968                 let m = [1, 2, 3].iter().filter_map(|x| if *x == 2 { Some (4) } else { None }).next();
969                       //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ replace filter_map(..).next() with find_map(..)
970             }
971         "#,
972         ));
973     }
974
975     #[test]
976     fn replace_filter_map_next_with_find_map_no_diagnostic_without_next() {
977         check_diagnostics(&add_filter_map_with_find_next_boilerplate(
978             r#"
979             fn foo() {
980                 let m = [1, 2, 3]
981                     .iter()
982                     .filter_map(|x| if *x == 2 { Some (4) } else { None })
983                     .len();
984             }
985             "#,
986         ));
987     }
988
989     #[test]
990     fn replace_filter_map_next_with_find_map_no_diagnostic_with_intervening_methods() {
991         check_diagnostics(&add_filter_map_with_find_next_boilerplate(
992             r#"
993             fn foo() {
994                 let m = [1, 2, 3]
995                     .iter()
996                     .filter_map(|x| if *x == 2 { Some (4) } else { None })
997                     .map(|x| x + 2)
998                     .len();
999             }
1000             "#,
1001         ));
1002     }
1003
1004     #[test]
1005     fn replace_filter_map_next_with_find_map_no_diagnostic_if_not_in_chain() {
1006         check_diagnostics(&add_filter_map_with_find_next_boilerplate(
1007             r#"
1008             fn foo() {
1009                 let m = [1, 2, 3]
1010                     .iter()
1011                     .filter_map(|x| if *x == 2 { Some (4) } else { None });
1012                 let n = m.next();
1013             }
1014             "#,
1015         ));
1016     }
1017
1018     #[test]
1019     fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
1020         check_diagnostics(
1021             r"
1022 struct S { foo: i32, bar: () }
1023 fn baz(s: S) -> i32 {
1024     match s {
1025         S { foo, .. } => foo,
1026     }
1027 }
1028 ",
1029         )
1030     }
1031
1032     #[test]
1033     fn missing_record_pat_field_box() {
1034         check_diagnostics(
1035             r"
1036 struct S { s: Box<u32> }
1037 fn x(a: S) {
1038     let S { box s } = a;
1039 }
1040 ",
1041         )
1042     }
1043
1044     #[test]
1045     fn missing_record_pat_field_ref() {
1046         check_diagnostics(
1047             r"
1048 struct S { s: u32 }
1049 fn x(a: S) {
1050     let S { ref s } = a;
1051 }
1052 ",
1053         )
1054     }
1055
1056     #[test]
1057     fn simple_free_fn_zero() {
1058         check_diagnostics(
1059             r#"
1060 fn zero() {}
1061 fn f() { zero(1); }
1062        //^^^^^^^ Expected 0 arguments, found 1
1063 "#,
1064         );
1065
1066         check_diagnostics(
1067             r#"
1068 fn zero() {}
1069 fn f() { zero(); }
1070 "#,
1071         );
1072     }
1073
1074     #[test]
1075     fn simple_free_fn_one() {
1076         check_diagnostics(
1077             r#"
1078 fn one(arg: u8) {}
1079 fn f() { one(); }
1080        //^^^^^ Expected 1 argument, found 0
1081 "#,
1082         );
1083
1084         check_diagnostics(
1085             r#"
1086 fn one(arg: u8) {}
1087 fn f() { one(1); }
1088 "#,
1089         );
1090     }
1091
1092     #[test]
1093     fn method_as_fn() {
1094         check_diagnostics(
1095             r#"
1096 struct S;
1097 impl S { fn method(&self) {} }
1098
1099 fn f() {
1100     S::method();
1101 } //^^^^^^^^^^^ Expected 1 argument, found 0
1102 "#,
1103         );
1104
1105         check_diagnostics(
1106             r#"
1107 struct S;
1108 impl S { fn method(&self) {} }
1109
1110 fn f() {
1111     S::method(&S);
1112     S.method();
1113 }
1114 "#,
1115         );
1116     }
1117
1118     #[test]
1119     fn method_with_arg() {
1120         check_diagnostics(
1121             r#"
1122 struct S;
1123 impl S { fn method(&self, arg: u8) {} }
1124
1125             fn f() {
1126                 S.method();
1127             } //^^^^^^^^^^ Expected 1 argument, found 0
1128             "#,
1129         );
1130
1131         check_diagnostics(
1132             r#"
1133 struct S;
1134 impl S { fn method(&self, arg: u8) {} }
1135
1136 fn f() {
1137     S::method(&S, 0);
1138     S.method(1);
1139 }
1140 "#,
1141         );
1142     }
1143
1144     #[test]
1145     fn method_unknown_receiver() {
1146         // note: this is incorrect code, so there might be errors on this in the
1147         // future, but we shouldn't emit an argument count diagnostic here
1148         check_diagnostics(
1149             r#"
1150 trait Foo { fn method(&self, arg: usize) {} }
1151
1152 fn f() {
1153     let x;
1154     x.method();
1155 }
1156 "#,
1157         );
1158     }
1159
1160     #[test]
1161     fn tuple_struct() {
1162         check_diagnostics(
1163             r#"
1164 struct Tup(u8, u16);
1165 fn f() {
1166     Tup(0);
1167 } //^^^^^^ Expected 2 arguments, found 1
1168 "#,
1169         )
1170     }
1171
1172     #[test]
1173     fn enum_variant() {
1174         check_diagnostics(
1175             r#"
1176 enum En { Variant(u8, u16), }
1177 fn f() {
1178     En::Variant(0);
1179 } //^^^^^^^^^^^^^^ Expected 2 arguments, found 1
1180 "#,
1181         )
1182     }
1183
1184     #[test]
1185     fn enum_variant_type_macro() {
1186         check_diagnostics(
1187             r#"
1188 macro_rules! Type {
1189     () => { u32 };
1190 }
1191 enum Foo {
1192     Bar(Type![])
1193 }
1194 impl Foo {
1195     fn new() {
1196         Foo::Bar(0);
1197         Foo::Bar(0, 1);
1198       //^^^^^^^^^^^^^^ Expected 1 argument, found 2
1199         Foo::Bar();
1200       //^^^^^^^^^^ Expected 1 argument, found 0
1201     }
1202 }
1203         "#,
1204         );
1205     }
1206
1207     #[test]
1208     fn varargs() {
1209         check_diagnostics(
1210             r#"
1211 extern "C" {
1212     fn fixed(fixed: u8);
1213     fn varargs(fixed: u8, ...);
1214     fn varargs2(...);
1215 }
1216
1217 fn f() {
1218     unsafe {
1219         fixed(0);
1220         fixed(0, 1);
1221       //^^^^^^^^^^^ Expected 1 argument, found 2
1222         varargs(0);
1223         varargs(0, 1);
1224         varargs2();
1225         varargs2(0);
1226         varargs2(0, 1);
1227     }
1228 }
1229         "#,
1230         )
1231     }
1232
1233     #[test]
1234     fn arg_count_lambda() {
1235         check_diagnostics(
1236             r#"
1237 fn main() {
1238     let f = |()| ();
1239     f();
1240   //^^^ Expected 1 argument, found 0
1241     f(());
1242     f((), ());
1243   //^^^^^^^^^ Expected 1 argument, found 2
1244 }
1245 "#,
1246         )
1247     }
1248
1249     #[test]
1250     fn cfgd_out_call_arguments() {
1251         check_diagnostics(
1252             r#"
1253 struct C(#[cfg(FALSE)] ());
1254 impl C {
1255     fn new() -> Self {
1256         Self(
1257             #[cfg(FALSE)]
1258             (),
1259         )
1260     }
1261
1262     fn method(&self) {}
1263 }
1264
1265 fn main() {
1266     C::new().method(#[cfg(FALSE)] 0);
1267 }
1268             "#,
1269         );
1270     }
1271
1272     #[test]
1273     fn cfgd_out_fn_params() {
1274         check_diagnostics(
1275             r#"
1276 fn foo(#[cfg(NEVER)] x: ()) {}
1277
1278 struct S;
1279
1280 impl S {
1281     fn method(#[cfg(NEVER)] self) {}
1282     fn method2(#[cfg(NEVER)] self, arg: u8) {}
1283     fn method3(self, #[cfg(NEVER)] arg: u8) {}
1284 }
1285
1286 extern "C" {
1287     fn fixed(fixed: u8, #[cfg(NEVER)] ...);
1288     fn varargs(#[cfg(not(NEVER))] ...);
1289 }
1290
1291 fn main() {
1292     foo();
1293     S::method();
1294     S::method2(0);
1295     S::method3(S);
1296     S.method3();
1297     unsafe {
1298         fixed(0);
1299         varargs(1, 2, 3);
1300     }
1301 }
1302             "#,
1303         )
1304     }
1305
1306     #[test]
1307     fn missing_semicolon() {
1308         check_diagnostics(
1309             r#"
1310                 fn test() -> i32 { 123; }
1311                                  //^^^ Remove this semicolon
1312             "#,
1313         );
1314     }
1315
1316     #[test]
1317     fn import_extern_crate_clash_with_inner_item() {
1318         // This is more of a resolver test, but doesn't really work with the hir_def testsuite.
1319
1320         check_diagnostics(
1321             r#"
1322 //- /lib.rs crate:lib deps:jwt
1323 mod permissions;
1324
1325 use permissions::jwt;
1326
1327 fn f() {
1328     fn inner() {}
1329     jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic
1330 }
1331
1332 //- /permissions.rs
1333 pub mod jwt  {
1334     pub struct Claims {}
1335 }
1336
1337 //- /jwt/lib.rs crate:jwt
1338 pub struct Claims {
1339     field: u8,
1340 }
1341         "#,
1342         );
1343     }
1344 }
1345
1346 #[cfg(test)]
1347 pub(super) mod match_check_tests {
1348     use crate::diagnostics::tests::check_diagnostics;
1349
1350     #[test]
1351     fn empty_tuple() {
1352         check_diagnostics(
1353             r#"
1354 fn main() {
1355     match () { }
1356         //^^ Missing match arm
1357     match (()) { }
1358         //^^^^ Missing match arm
1359
1360     match () { _ => (), }
1361     match () { () => (), }
1362     match (()) { (()) => (), }
1363 }
1364 "#,
1365         );
1366     }
1367
1368     #[test]
1369     fn tuple_of_two_empty_tuple() {
1370         check_diagnostics(
1371             r#"
1372 fn main() {
1373     match ((), ()) { }
1374         //^^^^^^^^ Missing match arm
1375
1376     match ((), ()) { ((), ()) => (), }
1377 }
1378 "#,
1379         );
1380     }
1381
1382     #[test]
1383     fn boolean() {
1384         check_diagnostics(
1385             r#"
1386 fn test_main() {
1387     match false { }
1388         //^^^^^ Missing match arm
1389     match false { true => (), }
1390         //^^^^^ Missing match arm
1391     match (false, true) {}
1392         //^^^^^^^^^^^^^ Missing match arm
1393     match (false, true) { (true, true) => (), }
1394         //^^^^^^^^^^^^^ Missing match arm
1395     match (false, true) {
1396         //^^^^^^^^^^^^^ Missing match arm
1397         (false, true) => (),
1398         (false, false) => (),
1399         (true, false) => (),
1400     }
1401     match (false, true) { (true, _x) => (), }
1402         //^^^^^^^^^^^^^ Missing match arm
1403
1404     match false { true => (), false => (), }
1405     match (false, true) {
1406         (false, _) => (),
1407         (true, false) => (),
1408         (_, true) => (),
1409     }
1410     match (false, true) {
1411         (true, true) => (),
1412         (true, false) => (),
1413         (false, true) => (),
1414         (false, false) => (),
1415     }
1416     match (false, true) {
1417         (true, _x) => (),
1418         (false, true) => (),
1419         (false, false) => (),
1420     }
1421     match (false, true, false) {
1422         (false, ..) => (),
1423         (true, ..) => (),
1424     }
1425     match (false, true, false) {
1426         (.., false) => (),
1427         (.., true) => (),
1428     }
1429     match (false, true, false) { (..) => (), }
1430 }
1431 "#,
1432         );
1433     }
1434
1435     #[test]
1436     fn tuple_of_tuple_and_bools() {
1437         check_diagnostics(
1438             r#"
1439 fn main() {
1440     match (false, ((), false)) {}
1441         //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1442     match (false, ((), false)) { (true, ((), true)) => (), }
1443         //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1444     match (false, ((), false)) { (true, _) => (), }
1445         //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1446
1447     match (false, ((), false)) {
1448         (true, ((), true)) => (),
1449         (true, ((), false)) => (),
1450         (false, ((), true)) => (),
1451         (false, ((), false)) => (),
1452     }
1453     match (false, ((), false)) {
1454         (true, ((), true)) => (),
1455         (true, ((), false)) => (),
1456         (false, _) => (),
1457     }
1458 }
1459 "#,
1460         );
1461     }
1462
1463     #[test]
1464     fn enums() {
1465         check_diagnostics(
1466             r#"
1467 enum Either { A, B, }
1468
1469 fn main() {
1470     match Either::A { }
1471         //^^^^^^^^^ Missing match arm
1472     match Either::B { Either::A => (), }
1473         //^^^^^^^^^ Missing match arm
1474
1475     match &Either::B {
1476         //^^^^^^^^^^ Missing match arm
1477         Either::A => (),
1478     }
1479
1480     match Either::B {
1481         Either::A => (), Either::B => (),
1482     }
1483     match &Either::B {
1484         Either::A => (), Either::B => (),
1485     }
1486 }
1487 "#,
1488         );
1489     }
1490
1491     #[test]
1492     fn enum_containing_bool() {
1493         check_diagnostics(
1494             r#"
1495 enum Either { A(bool), B }
1496
1497 fn main() {
1498     match Either::B { }
1499         //^^^^^^^^^ Missing match arm
1500     match Either::B {
1501         //^^^^^^^^^ Missing match arm
1502         Either::A(true) => (), Either::B => ()
1503     }
1504
1505     match Either::B {
1506         Either::A(true) => (),
1507         Either::A(false) => (),
1508         Either::B => (),
1509     }
1510     match Either::B {
1511         Either::B => (),
1512         _ => (),
1513     }
1514     match Either::B {
1515         Either::A(_) => (),
1516         Either::B => (),
1517     }
1518
1519 }
1520         "#,
1521         );
1522     }
1523
1524     #[test]
1525     fn enum_different_sizes() {
1526         check_diagnostics(
1527             r#"
1528 enum Either { A(bool), B(bool, bool) }
1529
1530 fn main() {
1531     match Either::A(false) {
1532         //^^^^^^^^^^^^^^^^ Missing match arm
1533         Either::A(_) => (),
1534         Either::B(false, _) => (),
1535     }
1536
1537     match Either::A(false) {
1538         Either::A(_) => (),
1539         Either::B(true, _) => (),
1540         Either::B(false, _) => (),
1541     }
1542     match Either::A(false) {
1543         Either::A(true) | Either::A(false) => (),
1544         Either::B(true, _) => (),
1545         Either::B(false, _) => (),
1546     }
1547 }
1548 "#,
1549         );
1550     }
1551
1552     #[test]
1553     fn tuple_of_enum_no_diagnostic() {
1554         check_diagnostics(
1555             r#"
1556 enum Either { A(bool), B(bool, bool) }
1557 enum Either2 { C, D }
1558
1559 fn main() {
1560     match (Either::A(false), Either2::C) {
1561         (Either::A(true), _) | (Either::A(false), _) => (),
1562         (Either::B(true, _), Either2::C) => (),
1563         (Either::B(false, _), Either2::C) => (),
1564         (Either::B(_, _), Either2::D) => (),
1565     }
1566 }
1567 "#,
1568         );
1569     }
1570
1571     #[test]
1572     fn or_pattern_no_diagnostic() {
1573         check_diagnostics(
1574             r#"
1575 enum Either {A, B}
1576
1577 fn main() {
1578     match (Either::A, Either::B) {
1579         (Either::A | Either::B, _) => (),
1580     }
1581 }"#,
1582         )
1583     }
1584
1585     #[test]
1586     fn mismatched_types() {
1587         // Match statements with arms that don't match the
1588         // expression pattern do not fire this diagnostic.
1589         check_diagnostics(
1590             r#"
1591 enum Either { A, B }
1592 enum Either2 { C, D }
1593
1594 fn main() {
1595     match Either::A {
1596         Either2::C => (),
1597     //  ^^^^^^^^^^ Internal: match check bailed out
1598         Either2::D => (),
1599     }
1600     match (true, false) {
1601         (true, false, true) => (),
1602     //  ^^^^^^^^^^^^^^^^^^^ Internal: match check bailed out
1603         (true) => (),
1604     }
1605     match (true, false) { (true,) => {} }
1606     //                    ^^^^^^^ Internal: match check bailed out
1607     match (0) { () => () }
1608             //  ^^ Internal: match check bailed out
1609     match Unresolved::Bar { Unresolved::Baz => () }
1610 }
1611         "#,
1612         );
1613     }
1614
1615     #[test]
1616     fn mismatched_types_in_or_patterns() {
1617         check_diagnostics(
1618             r#"
1619 fn main() {
1620     match false { true | () => {} }
1621     //            ^^^^^^^^^ Internal: match check bailed out
1622     match (false,) { (true | (),) => {} }
1623     //               ^^^^^^^^^^^^ Internal: match check bailed out
1624 }
1625 "#,
1626         );
1627     }
1628
1629     #[test]
1630     fn malformed_match_arm_tuple_enum_missing_pattern() {
1631         // We are testing to be sure we don't panic here when the match
1632         // arm `Either::B` is missing its pattern.
1633         check_diagnostics(
1634             r#"
1635 enum Either { A, B(u32) }
1636
1637 fn main() {
1638     match Either::A {
1639         Either::A => (),
1640         Either::B() => (),
1641     }
1642 }
1643 "#,
1644         );
1645     }
1646
1647     #[test]
1648     fn malformed_match_arm_extra_fields() {
1649         check_diagnostics(
1650             r#"
1651 enum A { B(isize, isize), C }
1652 fn main() {
1653     match A::B(1, 2) {
1654         A::B(_, _, _) => (),
1655     //  ^^^^^^^^^^^^^ Internal: match check bailed out
1656     }
1657     match A::B(1, 2) {
1658         A::C(_) => (),
1659     //  ^^^^^^^ Internal: match check bailed out
1660     }
1661 }
1662 "#,
1663         );
1664     }
1665
1666     #[test]
1667     fn expr_diverges() {
1668         check_diagnostics(
1669             r#"
1670 enum Either { A, B }
1671
1672 fn main() {
1673     match loop {} {
1674         Either::A => (),
1675     //  ^^^^^^^^^ Internal: match check bailed out
1676         Either::B => (),
1677     }
1678     match loop {} {
1679         Either::A => (),
1680     //  ^^^^^^^^^ Internal: match check bailed out
1681     }
1682     match loop { break Foo::A } {
1683         //^^^^^^^^^^^^^^^^^^^^^ Missing match arm
1684         Either::A => (),
1685     }
1686     match loop { break Foo::A } {
1687         Either::A => (),
1688         Either::B => (),
1689     }
1690 }
1691 "#,
1692         );
1693     }
1694
1695     #[test]
1696     fn expr_partially_diverges() {
1697         check_diagnostics(
1698             r#"
1699 enum Either<T> { A(T), B }
1700
1701 fn foo() -> Either<!> { Either::B }
1702 fn main() -> u32 {
1703     match foo() {
1704         Either::A(val) => val,
1705         Either::B => 0,
1706     }
1707 }
1708 "#,
1709         );
1710     }
1711
1712     #[test]
1713     fn enum_record() {
1714         check_diagnostics(
1715             r#"
1716 enum Either { A { foo: bool }, B }
1717
1718 fn main() {
1719     let a = Either::A { foo: true };
1720     match a { }
1721         //^ Missing match arm
1722     match a { Either::A { foo: true } => () }
1723         //^ Missing match arm
1724     match a {
1725         Either::A { } => (),
1726       //^^^^^^^^^ Missing structure fields:
1727       //        | - foo
1728         Either::B => (),
1729     }
1730     match a {
1731         //^ Missing match arm
1732         Either::A { } => (),
1733     } //^^^^^^^^^ Missing structure fields:
1734       //        | - foo
1735
1736     match a {
1737         Either::A { foo: true } => (),
1738         Either::A { foo: false } => (),
1739         Either::B => (),
1740     }
1741     match a {
1742         Either::A { foo: _ } => (),
1743         Either::B => (),
1744     }
1745 }
1746 "#,
1747         );
1748     }
1749
1750     #[test]
1751     fn enum_record_fields_out_of_order() {
1752         check_diagnostics(
1753             r#"
1754 enum Either {
1755     A { foo: bool, bar: () },
1756     B,
1757 }
1758
1759 fn main() {
1760     let a = Either::A { foo: true, bar: () };
1761     match a {
1762         //^ Missing match arm
1763         Either::A { bar: (), foo: false } => (),
1764         Either::A { foo: true, bar: () } => (),
1765     }
1766
1767     match a {
1768         Either::A { bar: (), foo: false } => (),
1769         Either::A { foo: true, bar: () } => (),
1770         Either::B => (),
1771     }
1772 }
1773 "#,
1774         );
1775     }
1776
1777     #[test]
1778     fn enum_record_ellipsis() {
1779         check_diagnostics(
1780             r#"
1781 enum Either {
1782     A { foo: bool, bar: bool },
1783     B,
1784 }
1785
1786 fn main() {
1787     let a = Either::B;
1788     match a {
1789         //^ Missing match arm
1790         Either::A { foo: true, .. } => (),
1791         Either::B => (),
1792     }
1793     match a {
1794         //^ Missing match arm
1795         Either::A { .. } => (),
1796     }
1797
1798     match a {
1799         Either::A { foo: true, .. } => (),
1800         Either::A { foo: false, .. } => (),
1801         Either::B => (),
1802     }
1803
1804     match a {
1805         Either::A { .. } => (),
1806         Either::B => (),
1807     }
1808 }
1809 "#,
1810         );
1811     }
1812
1813     #[test]
1814     fn enum_tuple_partial_ellipsis() {
1815         check_diagnostics(
1816             r#"
1817 enum Either {
1818     A(bool, bool, bool, bool),
1819     B,
1820 }
1821
1822 fn main() {
1823     match Either::B {
1824         //^^^^^^^^^ Missing match arm
1825         Either::A(true, .., true) => (),
1826         Either::A(true, .., false) => (),
1827         Either::A(false, .., false) => (),
1828         Either::B => (),
1829     }
1830     match Either::B {
1831         //^^^^^^^^^ Missing match arm
1832         Either::A(true, .., true) => (),
1833         Either::A(true, .., false) => (),
1834         Either::A(.., true) => (),
1835         Either::B => (),
1836     }
1837
1838     match Either::B {
1839         Either::A(true, .., true) => (),
1840         Either::A(true, .., false) => (),
1841         Either::A(false, .., true) => (),
1842         Either::A(false, .., false) => (),
1843         Either::B => (),
1844     }
1845     match Either::B {
1846         Either::A(true, .., true) => (),
1847         Either::A(true, .., false) => (),
1848         Either::A(.., true) => (),
1849         Either::A(.., false) => (),
1850         Either::B => (),
1851     }
1852 }
1853 "#,
1854         );
1855     }
1856
1857     #[test]
1858     fn never() {
1859         check_diagnostics(
1860             r#"
1861 enum Never {}
1862
1863 fn enum_(never: Never) {
1864     match never {}
1865 }
1866 fn enum_ref(never: &Never) {
1867     match never {}
1868         //^^^^^ Missing match arm
1869 }
1870 fn bang(never: !) {
1871     match never {}
1872 }
1873 "#,
1874         );
1875     }
1876
1877     #[test]
1878     fn unknown_type() {
1879         check_diagnostics(
1880             r#"
1881 enum Option<T> { Some(T), None }
1882
1883 fn main() {
1884     // `Never` is deliberately not defined so that it's an uninferred type.
1885     match Option::<Never>::None {
1886         None => (),
1887         Some(never) => match never {},
1888     //  ^^^^^^^^^^^ Internal: match check bailed out
1889     }
1890     match Option::<Never>::None {
1891         //^^^^^^^^^^^^^^^^^^^^^ Missing match arm
1892         Option::Some(_never) => {},
1893     }
1894 }
1895 "#,
1896         );
1897     }
1898
1899     #[test]
1900     fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
1901         check_diagnostics(
1902             r#"
1903 fn main() {
1904     match (false, true, false) {
1905         //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1906         (false, ..) => (),
1907     }
1908 }"#,
1909         );
1910     }
1911
1912     #[test]
1913     fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
1914         check_diagnostics(
1915             r#"
1916 fn main() {
1917     match (false, true, false) {
1918         //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1919         (.., false) => (),
1920     }
1921 }"#,
1922         );
1923     }
1924
1925     #[test]
1926     fn tuple_of_bools_with_ellipsis_in_middle_missing_arm() {
1927         check_diagnostics(
1928             r#"
1929 fn main() {
1930     match (false, true, false) {
1931         //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1932         (true, .., false) => (),
1933     }
1934 }"#,
1935         );
1936     }
1937
1938     #[test]
1939     fn record_struct() {
1940         check_diagnostics(
1941             r#"struct Foo { a: bool }
1942 fn main(f: Foo) {
1943     match f {}
1944         //^ Missing match arm
1945     match f { Foo { a: true } => () }
1946         //^ Missing match arm
1947     match &f { Foo { a: true } => () }
1948         //^^ Missing match arm
1949     match f { Foo { a: _ } => () }
1950     match f {
1951         Foo { a: true } => (),
1952         Foo { a: false } => (),
1953     }
1954     match &f {
1955         Foo { a: true } => (),
1956         Foo { a: false } => (),
1957     }
1958 }
1959 "#,
1960         );
1961     }
1962
1963     #[test]
1964     fn tuple_struct() {
1965         check_diagnostics(
1966             r#"struct Foo(bool);
1967 fn main(f: Foo) {
1968     match f {}
1969         //^ Missing match arm
1970     match f { Foo(true) => () }
1971         //^ Missing match arm
1972     match f {
1973         Foo(true) => (),
1974         Foo(false) => (),
1975     }
1976 }
1977 "#,
1978         );
1979     }
1980
1981     #[test]
1982     fn unit_struct() {
1983         check_diagnostics(
1984             r#"struct Foo;
1985 fn main(f: Foo) {
1986     match f {}
1987         //^ Missing match arm
1988     match f { Foo => () }
1989 }
1990 "#,
1991         );
1992     }
1993
1994     #[test]
1995     fn record_struct_ellipsis() {
1996         check_diagnostics(
1997             r#"struct Foo { foo: bool, bar: bool }
1998 fn main(f: Foo) {
1999     match f { Foo { foo: true, .. } => () }
2000         //^ Missing match arm
2001     match f {
2002         //^ Missing match arm
2003         Foo { foo: true, .. } => (),
2004         Foo { bar: false, .. } => ()
2005     }
2006     match f { Foo { .. } => () }
2007     match f {
2008         Foo { foo: true, .. } => (),
2009         Foo { foo: false, .. } => ()
2010     }
2011 }
2012 "#,
2013         );
2014     }
2015
2016     #[test]
2017     fn internal_or() {
2018         check_diagnostics(
2019             r#"
2020 fn main() {
2021     enum Either { A(bool), B }
2022     match Either::B {
2023         //^^^^^^^^^ Missing match arm
2024         Either::A(true | false) => (),
2025     }
2026 }
2027 "#,
2028         );
2029     }
2030
2031     #[test]
2032     fn no_panic_at_unimplemented_subpattern_type() {
2033         check_diagnostics(
2034             r#"
2035 struct S { a: char}
2036 fn main(v: S) {
2037     match v { S{ a }      => {} }
2038     match v { S{ a: _x }  => {} }
2039     match v { S{ a: 'a' } => {} }
2040             //^^^^^^^^^^^ Internal: match check bailed out
2041     match v { S{..}       => {} }
2042     match v { _           => {} }
2043     match v { }
2044         //^ Missing match arm
2045 }
2046 "#,
2047         );
2048     }
2049
2050     #[test]
2051     fn binding() {
2052         check_diagnostics(
2053             r#"
2054 fn main() {
2055     match true {
2056         _x @ true => {}
2057         false     => {}
2058     }
2059     match true { _x @ true => {} }
2060         //^^^^ Missing match arm
2061 }
2062 "#,
2063         );
2064     }
2065
2066     #[test]
2067     fn binding_ref_has_correct_type() {
2068         // Asserts `PatKind::Binding(ref _x): bool`, not &bool.
2069         // If that's not true match checking will panic with "incompatible constructors"
2070         // FIXME: make facilities to test this directly like `tests::check_infer(..)`
2071         check_diagnostics(
2072             r#"
2073 enum Foo { A }
2074 fn main() {
2075     // FIXME: this should not bail out but current behavior is such as the old algorithm.
2076     // ExprValidator::validate_match(..) checks types of top level patterns incorrecly.
2077     match Foo::A {
2078         ref _x => {}
2079     //  ^^^^^^ Internal: match check bailed out
2080         Foo::A => {}
2081     }
2082     match (true,) {
2083         (ref _x,) => {}
2084         (true,) => {}
2085     }
2086 }
2087 "#,
2088         );
2089     }
2090
2091     #[test]
2092     fn enum_non_exhaustive() {
2093         check_diagnostics(
2094             r#"
2095 //- /lib.rs crate:lib
2096 #[non_exhaustive]
2097 pub enum E { A, B }
2098 fn _local() {
2099     match E::A { _ => {} }
2100     match E::A {
2101         E::A => {}
2102         E::B => {}
2103     }
2104     match E::A {
2105         E::A | E::B => {}
2106     }
2107 }
2108
2109 //- /main.rs crate:main deps:lib
2110 use lib::E;
2111 fn main() {
2112     match E::A { _ => {} }
2113     match E::A {
2114         //^^^^ Missing match arm
2115         E::A => {}
2116         E::B => {}
2117     }
2118     match E::A {
2119         //^^^^ Missing match arm
2120         E::A | E::B => {}
2121     }
2122 }
2123 "#,
2124         );
2125     }
2126
2127     #[test]
2128     fn match_guard() {
2129         check_diagnostics(
2130             r#"
2131 fn main() {
2132     match true {
2133         true if false => {}
2134         true          => {}
2135         false         => {}
2136     }
2137     match true {
2138         //^^^^ Missing match arm
2139         true if false => {}
2140         false         => {}
2141     }
2142 }
2143 "#,
2144         );
2145     }
2146
2147     #[test]
2148     fn pattern_type_is_of_substitution() {
2149         cov_mark::check!(match_check_wildcard_expanded_to_substitutions);
2150         check_diagnostics(
2151             r#"
2152 struct Foo<T>(T);
2153 struct Bar;
2154 fn main() {
2155     match Foo(Bar) {
2156         _ | Foo(Bar) => {}
2157     }
2158 }
2159 "#,
2160         );
2161     }
2162
2163     #[test]
2164     fn record_struct_no_such_field() {
2165         check_diagnostics(
2166             r#"
2167 struct Foo { }
2168 fn main(f: Foo) {
2169     match f { Foo { bar } => () }
2170     //        ^^^^^^^^^^^ Internal: match check bailed out
2171 }
2172 "#,
2173         );
2174     }
2175
2176     #[test]
2177     fn match_ergonomics_issue_9095() {
2178         check_diagnostics(
2179             r#"
2180 enum Foo<T> { A(T) }
2181 fn main() {
2182     match &Foo::A(true) {
2183         _ => {}
2184         Foo::A(_) => {}
2185     }
2186 }
2187 "#,
2188         );
2189     }
2190
2191     mod false_negatives {
2192         //! The implementation of match checking here is a work in progress. As we roll this out, we
2193         //! prefer false negatives to false positives (ideally there would be no false positives). This
2194         //! test module should document known false negatives. Eventually we will have a complete
2195         //! implementation of match checking and this module will be empty.
2196         //!
2197         //! The reasons for documenting known false negatives:
2198         //!
2199         //!   1. It acts as a backlog of work that can be done to improve the behavior of the system.
2200         //!   2. It ensures the code doesn't panic when handling these cases.
2201         use super::*;
2202
2203         #[test]
2204         fn integers() {
2205             // We don't currently check integer exhaustiveness.
2206             check_diagnostics(
2207                 r#"
2208 fn main() {
2209     match 5 {
2210         10 => (),
2211     //  ^^ Internal: match check bailed out
2212         11..20 => (),
2213     }
2214 }
2215 "#,
2216             );
2217         }
2218
2219         #[test]
2220         fn reference_patterns_at_top_level() {
2221             check_diagnostics(
2222                 r#"
2223 fn main() {
2224     match &false {
2225         &true => {}
2226     //  ^^^^^ Internal: match check bailed out
2227     }
2228 }
2229             "#,
2230             );
2231         }
2232
2233         #[test]
2234         fn reference_patterns_in_fields() {
2235             check_diagnostics(
2236                 r#"
2237 fn main() {
2238     match (&false,) {
2239         (true,) => {}
2240     //  ^^^^^^^ Internal: match check bailed out
2241     }
2242     match (&false,) {
2243         (&true,) => {}
2244     //  ^^^^^^^^ Internal: match check bailed out
2245     }
2246 }
2247             "#,
2248             );
2249         }
2250     }
2251 }
2252
2253 #[cfg(test)]
2254 mod decl_check_tests {
2255     use crate::diagnostics::tests::check_diagnostics;
2256
2257     #[test]
2258     fn incorrect_function_name() {
2259         check_diagnostics(
2260             r#"
2261 fn NonSnakeCaseName() {}
2262 // ^^^^^^^^^^^^^^^^ Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name`
2263 "#,
2264         );
2265     }
2266
2267     #[test]
2268     fn incorrect_function_params() {
2269         check_diagnostics(
2270             r#"
2271 fn foo(SomeParam: u8) {}
2272     // ^^^^^^^^^ Parameter `SomeParam` should have snake_case name, e.g. `some_param`
2273
2274 fn foo2(ok_param: &str, CAPS_PARAM: u8) {}
2275                      // ^^^^^^^^^^ Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param`
2276 "#,
2277         );
2278     }
2279
2280     #[test]
2281     fn incorrect_variable_names() {
2282         check_diagnostics(
2283             r#"
2284 fn foo() {
2285     let SOME_VALUE = 10;
2286      // ^^^^^^^^^^ Variable `SOME_VALUE` should have snake_case name, e.g. `some_value`
2287     let AnotherValue = 20;
2288      // ^^^^^^^^^^^^ Variable `AnotherValue` should have snake_case name, e.g. `another_value`
2289 }
2290 "#,
2291         );
2292     }
2293
2294     #[test]
2295     fn incorrect_struct_names() {
2296         check_diagnostics(
2297             r#"
2298 struct non_camel_case_name {}
2299     // ^^^^^^^^^^^^^^^^^^^ Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName`
2300
2301 struct SCREAMING_CASE {}
2302     // ^^^^^^^^^^^^^^ Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase`
2303 "#,
2304         );
2305     }
2306
2307     #[test]
2308     fn no_diagnostic_for_camel_cased_acronyms_in_struct_name() {
2309         check_diagnostics(
2310             r#"
2311 struct AABB {}
2312 "#,
2313         );
2314     }
2315
2316     #[test]
2317     fn incorrect_struct_field() {
2318         check_diagnostics(
2319             r#"
2320 struct SomeStruct { SomeField: u8 }
2321                  // ^^^^^^^^^ Field `SomeField` should have snake_case name, e.g. `some_field`
2322 "#,
2323         );
2324     }
2325
2326     #[test]
2327     fn incorrect_enum_names() {
2328         check_diagnostics(
2329             r#"
2330 enum some_enum { Val(u8) }
2331   // ^^^^^^^^^ Enum `some_enum` should have CamelCase name, e.g. `SomeEnum`
2332
2333 enum SOME_ENUM {}
2334   // ^^^^^^^^^ Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum`
2335 "#,
2336         );
2337     }
2338
2339     #[test]
2340     fn no_diagnostic_for_camel_cased_acronyms_in_enum_name() {
2341         check_diagnostics(
2342             r#"
2343 enum AABB {}
2344 "#,
2345         );
2346     }
2347
2348     #[test]
2349     fn incorrect_enum_variant_name() {
2350         check_diagnostics(
2351             r#"
2352 enum SomeEnum { SOME_VARIANT(u8) }
2353              // ^^^^^^^^^^^^ Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant`
2354 "#,
2355         );
2356     }
2357
2358     #[test]
2359     fn incorrect_const_name() {
2360         check_diagnostics(
2361             r#"
2362 const some_weird_const: u8 = 10;
2363    // ^^^^^^^^^^^^^^^^ Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
2364 "#,
2365         );
2366     }
2367
2368     #[test]
2369     fn incorrect_static_name() {
2370         check_diagnostics(
2371             r#"
2372 static some_weird_const: u8 = 10;
2373     // ^^^^^^^^^^^^^^^^ Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
2374 "#,
2375         );
2376     }
2377
2378     #[test]
2379     fn fn_inside_impl_struct() {
2380         check_diagnostics(
2381             r#"
2382 struct someStruct;
2383     // ^^^^^^^^^^ Structure `someStruct` should have CamelCase name, e.g. `SomeStruct`
2384
2385 impl someStruct {
2386     fn SomeFunc(&self) {
2387     // ^^^^^^^^ Function `SomeFunc` should have snake_case name, e.g. `some_func`
2388         let WHY_VAR_IS_CAPS = 10;
2389          // ^^^^^^^^^^^^^^^ Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps`
2390     }
2391 }
2392 "#,
2393         );
2394     }
2395
2396     #[test]
2397     fn no_diagnostic_for_enum_varinats() {
2398         check_diagnostics(
2399             r#"
2400 enum Option { Some, None }
2401
2402 fn main() {
2403     match Option::None {
2404         None => (),
2405         Some => (),
2406     }
2407 }
2408 "#,
2409         );
2410     }
2411
2412     #[test]
2413     fn non_let_bind() {
2414         check_diagnostics(
2415             r#"
2416 enum Option { Some, None }
2417
2418 fn main() {
2419     match Option::None {
2420         SOME_VAR @ None => (),
2421      // ^^^^^^^^ Variable `SOME_VAR` should have snake_case name, e.g. `some_var`
2422         Some => (),
2423     }
2424 }
2425 "#,
2426         );
2427     }
2428
2429     #[test]
2430     fn allow_attributes() {
2431         check_diagnostics(
2432             r#"
2433 #[allow(non_snake_case)]
2434 fn NonSnakeCaseName(SOME_VAR: u8) -> u8{
2435     // cov_flags generated output from elsewhere in this file
2436     extern "C" {
2437         #[no_mangle]
2438         static lower_case: u8;
2439     }
2440
2441     let OtherVar = SOME_VAR + 1;
2442     OtherVar
2443 }
2444
2445 #[allow(nonstandard_style)]
2446 mod CheckNonstandardStyle {
2447     fn HiImABadFnName() {}
2448 }
2449
2450 #[allow(bad_style)]
2451 mod CheckBadStyle {
2452     fn HiImABadFnName() {}
2453 }
2454
2455 mod F {
2456     #![allow(non_snake_case)]
2457     fn CheckItWorksWithModAttr(BAD_NAME_HI: u8) {}
2458 }
2459
2460 #[allow(non_snake_case, non_camel_case_types)]
2461 pub struct some_type {
2462     SOME_FIELD: u8,
2463     SomeField: u16,
2464 }
2465
2466 #[allow(non_upper_case_globals)]
2467 pub const some_const: u8 = 10;
2468
2469 #[allow(non_upper_case_globals)]
2470 pub static SomeStatic: u8 = 10;
2471     "#,
2472         );
2473     }
2474
2475     #[test]
2476     fn allow_attributes_crate_attr() {
2477         check_diagnostics(
2478             r#"
2479 #![allow(non_snake_case)]
2480
2481 mod F {
2482     fn CheckItWorksWithCrateAttr(BAD_NAME_HI: u8) {}
2483 }
2484     "#,
2485         );
2486     }
2487
2488     #[test]
2489     #[ignore]
2490     fn bug_trait_inside_fn() {
2491         // FIXME:
2492         // This is broken, and in fact, should not even be looked at by this
2493         // lint in the first place. There's weird stuff going on in the
2494         // collection phase.
2495         // It's currently being brought in by:
2496         // * validate_func on `a` recursing into modules
2497         // * then it finds the trait and then the function while iterating
2498         //   through modules
2499         // * then validate_func is called on Dirty
2500         // * ... which then proceeds to look at some unknown module taking no
2501         //   attrs from either the impl or the fn a, and then finally to the root
2502         //   module
2503         //
2504         // It should find the attribute on the trait, but it *doesn't even see
2505         // the trait* as far as I can tell.
2506
2507         check_diagnostics(
2508             r#"
2509 trait T { fn a(); }
2510 struct U {}
2511 impl T for U {
2512     fn a() {
2513         // this comes out of bitflags, mostly
2514         #[allow(non_snake_case)]
2515         trait __BitFlags {
2516             const HiImAlsoBad: u8 = 2;
2517             #[inline]
2518             fn Dirty(&self) -> bool {
2519                 false
2520             }
2521         }
2522
2523     }
2524 }
2525     "#,
2526         );
2527     }
2528
2529     #[test]
2530     #[ignore]
2531     fn bug_traits_arent_checked() {
2532         // FIXME: Traits and functions in traits aren't currently checked by
2533         // r-a, even though rustc will complain about them.
2534         check_diagnostics(
2535             r#"
2536 trait BAD_TRAIT {
2537     // ^^^^^^^^^ Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait`
2538     fn BAD_FUNCTION();
2539     // ^^^^^^^^^^^^ Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function`
2540     fn BadFunction();
2541     // ^^^^^^^^^^^^ Function `BadFunction` should have snake_case name, e.g. `bad_function`
2542 }
2543     "#,
2544         );
2545     }
2546
2547     #[test]
2548     fn ignores_extern_items() {
2549         cov_mark::check!(extern_func_incorrect_case_ignored);
2550         cov_mark::check!(extern_static_incorrect_case_ignored);
2551         check_diagnostics(
2552             r#"
2553 extern {
2554     fn NonSnakeCaseName(SOME_VAR: u8) -> u8;
2555     pub static SomeStatic: u8 = 10;
2556 }
2557             "#,
2558         );
2559     }
2560
2561     #[test]
2562     fn infinite_loop_inner_items() {
2563         check_diagnostics(
2564             r#"
2565 fn qualify() {
2566     mod foo {
2567         use super::*;
2568     }
2569 }
2570             "#,
2571         )
2572     }
2573
2574     #[test] // Issue #8809.
2575     fn parenthesized_parameter() {
2576         check_diagnostics(r#"fn f((O): _) {}"#)
2577     }
2578 }