]> git.lizzy.rs Git - rust.git/blob - crates/ide_diagnostics/src/handlers/unresolved_module.rs
Merge #11878
[rust.git] / crates / ide_diagnostics / src / handlers / unresolved_module.rs
1 use hir::db::AstDatabase;
2 use ide_db::{assists::Assist, base_db::AnchoredPathBuf, source_change::FileSystemEdit};
3 use itertools::Itertools;
4 use syntax::AstNode;
5
6 use crate::{fix, Diagnostic, DiagnosticsContext};
7
8 // Diagnostic: unresolved-module
9 //
10 // This diagnostic is triggered if rust-analyzer is unable to discover referred module.
11 pub(crate) fn unresolved_module(
12     ctx: &DiagnosticsContext<'_>,
13     d: &hir::UnresolvedModule,
14 ) -> Diagnostic {
15     Diagnostic::new(
16         "unresolved-module",
17         match &*d.candidates {
18             [] => "unresolved module".to_string(),
19             [candidate] => format!("unresolved module, can't find module file: {}", candidate),
20             [candidates @ .., last] => {
21                 format!(
22                     "unresolved module, can't find module file: {}, or {}",
23                     candidates.iter().format(", "),
24                     last
25                 )
26             }
27         },
28         ctx.sema.diagnostics_display_range(d.decl.clone().map(|it| it.into())).range,
29     )
30     .with_fixes(fixes(ctx, d))
31 }
32
33 fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedModule) -> Option<Vec<Assist>> {
34     let root = ctx.sema.db.parse_or_expand(d.decl.file_id)?;
35     let unresolved_module = d.decl.value.to_node(&root);
36     Some(
37         d.candidates
38             .iter()
39             .map(|candidate| {
40                 fix(
41                     "create_module",
42                     "Create module",
43                     FileSystemEdit::CreateFile {
44                         dst: AnchoredPathBuf {
45                             anchor: d.decl.file_id.original_file(ctx.sema.db),
46                             path: candidate.clone(),
47                         },
48                         initial_contents: "".to_string(),
49                     }
50                     .into(),
51                     unresolved_module.syntax().text_range(),
52                 )
53             })
54             .collect(),
55     )
56 }
57
58 #[cfg(test)]
59 mod tests {
60     use expect_test::expect;
61
62     use crate::tests::{check_diagnostics, check_expect};
63
64     #[test]
65     fn unresolved_module() {
66         check_diagnostics(
67             r#"
68 //- /lib.rs
69 mod foo;
70   mod bar;
71 //^^^^^^^^ ðŸ’¡ error: unresolved module, can't find module file: bar.rs, or bar/mod.rs
72 mod baz {}
73 //- /foo.rs
74 "#,
75         );
76     }
77
78     #[test]
79     fn test_unresolved_module_diagnostic() {
80         check_expect(
81             r#"mod foo;"#,
82             expect![[r#"
83                 [
84                     Diagnostic {
85                         code: DiagnosticCode(
86                             "unresolved-module",
87                         ),
88                         message: "unresolved module, can't find module file: foo.rs, or foo/mod.rs",
89                         range: 0..8,
90                         severity: Error,
91                         unused: false,
92                         experimental: false,
93                         fixes: Some(
94                             [
95                                 Assist {
96                                     id: AssistId(
97                                         "create_module",
98                                         QuickFix,
99                                     ),
100                                     label: "Create module",
101                                     group: None,
102                                     target: 0..8,
103                                     source_change: Some(
104                                         SourceChange {
105                                             source_file_edits: {},
106                                             file_system_edits: [
107                                                 CreateFile {
108                                                     dst: AnchoredPathBuf {
109                                                         anchor: FileId(
110                                                             0,
111                                                         ),
112                                                         path: "foo.rs",
113                                                     },
114                                                     initial_contents: "",
115                                                 },
116                                             ],
117                                             is_snippet: false,
118                                         },
119                                     ),
120                                 },
121                                 Assist {
122                                     id: AssistId(
123                                         "create_module",
124                                         QuickFix,
125                                     ),
126                                     label: "Create module",
127                                     group: None,
128                                     target: 0..8,
129                                     source_change: Some(
130                                         SourceChange {
131                                             source_file_edits: {},
132                                             file_system_edits: [
133                                                 CreateFile {
134                                                     dst: AnchoredPathBuf {
135                                                         anchor: FileId(
136                                                             0,
137                                                         ),
138                                                         path: "foo/mod.rs",
139                                                     },
140                                                     initial_contents: "",
141                                                 },
142                                             ],
143                                             is_snippet: false,
144                                         },
145                                     ),
146                                 },
147                             ],
148                         ),
149                     },
150                 ]
151             "#]],
152         );
153     }
154 }