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