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