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