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