]> git.lizzy.rs Git - rust.git/blob - crates/ide_diagnostics/src/handlers/macro_error.rs
Merge #11354
[rust.git] / crates / ide_diagnostics / src / handlers / macro_error.rs
1 use crate::{Diagnostic, DiagnosticsContext};
2
3 // Diagnostic: macro-error
4 //
5 // This diagnostic is shown for macro expansion errors.
6 pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic {
7     Diagnostic::new(
8         "macro-error",
9         d.message.clone(),
10         ctx.sema.diagnostics_display_range(d.node.clone()).range,
11     )
12     .experimental()
13 }
14
15 #[cfg(test)]
16 mod tests {
17     use crate::{
18         tests::{check_diagnostics, check_diagnostics_with_config},
19         DiagnosticsConfig,
20     };
21
22     #[test]
23     fn builtin_macro_fails_expansion() {
24         check_diagnostics(
25             r#"
26 #[rustc_builtin_macro]
27 macro_rules! include { () => {} }
28
29 #[rustc_builtin_macro]
30 macro_rules! compile_error { () => {} }
31
32   include!("doesntexist");
33 //^^^^^^^^^^^^^^^^^^^^^^^^ error: failed to load file `doesntexist`
34
35   compile_error!("compile_error macro works");
36 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: compile_error macro works
37             "#,
38         );
39     }
40
41     #[test]
42     fn eager_macro_concat() {
43         // FIXME: this is incorrectly handling `$crate`, resulting in a wrong diagnostic.
44         // See: https://github.com/rust-analyzer/rust-analyzer/issues/10300
45
46         check_diagnostics(
47             r#"
48 //- /lib.rs crate:lib deps:core
49 use core::{panic, concat};
50
51 mod private {
52     pub use core::concat;
53 }
54
55 macro_rules! m {
56     () => {
57         panic!(concat!($crate::private::concat!("")));
58     };
59 }
60
61 fn f() {
62     m!();
63   //^^^^ error: unresolved macro `$crate::private::concat!`
64 }
65
66 //- /core.rs crate:core
67 #[macro_export]
68 #[rustc_builtin_macro]
69 macro_rules! concat { () => {} }
70
71 pub macro panic {
72     ($msg:expr) => (
73         $crate::panicking::panic_str($msg)
74     ),
75 }
76             "#,
77         );
78     }
79
80     #[test]
81     fn include_macro_should_allow_empty_content() {
82         let mut config = DiagnosticsConfig::default();
83
84         // FIXME: This is a false-positive, the file is actually linked in via
85         // `include!` macro
86         config.disabled.insert("unlinked-file".to_string());
87
88         check_diagnostics_with_config(
89             config,
90             r#"
91 //- /lib.rs
92 #[rustc_builtin_macro]
93 macro_rules! include { () => {} }
94
95 include!("foo/bar.rs");
96 //- /foo/bar.rs
97 // empty
98 "#,
99         );
100     }
101
102     #[test]
103     fn good_out_dir_diagnostic() {
104         check_diagnostics(
105             r#"
106 #[rustc_builtin_macro]
107 macro_rules! include { () => {} }
108 #[rustc_builtin_macro]
109 macro_rules! env { () => {} }
110 #[rustc_builtin_macro]
111 macro_rules! concat { () => {} }
112
113   include!(concat!(env!("OUT_DIR"), "/out.rs"));
114 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `OUT_DIR` not set, enable "run build scripts" to fix
115 "#,
116         );
117     }
118
119     #[test]
120     fn register_attr_and_tool() {
121         cov_mark::check!(register_attr);
122         cov_mark::check!(register_tool);
123         check_diagnostics(
124             r#"
125 #![register_tool(tool)]
126 #![register_attr(attr)]
127
128 #[tool::path]
129 #[attr]
130 struct S;
131 "#,
132         );
133         // NB: we don't currently emit diagnostics here
134     }
135
136     #[test]
137     fn macro_diag_builtin() {
138         check_diagnostics(
139             r#"
140 #[rustc_builtin_macro]
141 macro_rules! env {}
142
143 #[rustc_builtin_macro]
144 macro_rules! include {}
145
146 #[rustc_builtin_macro]
147 macro_rules! compile_error {}
148
149 #[rustc_builtin_macro]
150 macro_rules! format_args { () => {} }
151
152 fn main() {
153     // Test a handful of built-in (eager) macros:
154
155     include!(invalid);
156   //^^^^^^^^^^^^^^^^^ error: could not convert tokens
157     include!("does not exist");
158   //^^^^^^^^^^^^^^^^^^^^^^^^^^ error: failed to load file `does not exist`
159
160     env!(invalid);
161   //^^^^^^^^^^^^^ error: could not convert tokens
162
163     env!("OUT_DIR");
164   //^^^^^^^^^^^^^^^ error: `OUT_DIR` not set, enable "run build scripts" to fix
165
166     compile_error!("compile_error works");
167   //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: compile_error works
168
169     // Lazy:
170
171     format_args!();
172   //^^^^^^^^^^^^^^ error: no rule matches input tokens
173 }
174 "#,
175         );
176     }
177
178     #[test]
179     fn macro_rules_diag() {
180         check_diagnostics(
181             r#"
182 macro_rules! m {
183     () => {};
184 }
185 fn f() {
186     m!();
187
188     m!(hi);
189   //^^^^^^ error: leftover tokens
190 }
191       "#,
192         );
193     }
194     #[test]
195     fn dollar_crate_in_builtin_macro() {
196         check_diagnostics(
197             r#"
198 #[macro_export]
199 #[rustc_builtin_macro]
200 macro_rules! format_args {}
201
202 #[macro_export]
203 macro_rules! arg { () => {} }
204
205 #[macro_export]
206 macro_rules! outer {
207     () => {
208         $crate::format_args!( "", $crate::arg!(1) )
209     };
210 }
211
212 fn f() {
213     outer!();
214 } //^^^^^^^^ error: leftover tokens
215 "#,
216         )
217     }
218 }