ra_ap_ide_diagnostics/handlers/
macro_error.rs1use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, Severity};
2
3pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic {
15 let display_range = ctx.resolve_precise_location(&d.node, d.precise_location);
17 Diagnostic::new(
18 DiagnosticCode::Ra(d.kind, if d.error { Severity::Error } else { Severity::WeakWarning }),
19 d.message.clone(),
20 display_range,
21 )
22 .stable()
23}
24
25pub(crate) fn macro_def_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroDefError) -> Diagnostic {
29 let display_range =
31 ctx.resolve_precise_location(&d.node.map(|it| it.syntax_node_ptr()), d.name);
32 Diagnostic::new(
33 DiagnosticCode::Ra("macro-def-error", Severity::Error),
34 d.message.clone(),
35 display_range,
36 )
37 .stable()
38}
39
40#[cfg(test)]
41mod tests {
42 use crate::{
43 DiagnosticsConfig,
44 tests::{check_diagnostics, check_diagnostics_with_config},
45 };
46
47 #[test]
48 fn builtin_macro_fails_expansion() {
49 check_diagnostics(
50 r#"
51#[rustc_builtin_macro]
52macro_rules! include { () => {} }
53
54#[rustc_builtin_macro]
55macro_rules! compile_error { () => {} }
56
57 include!("doesntexist");
58 //^^^^^^^^^^^^^ error: failed to load file `doesntexist`
59
60 compile_error!("compile_error macro works");
61//^^^^^^^^^^^^^ error: compile_error macro works
62
63 compile_error! { "compile_error macro braced works" }
64//^^^^^^^^^^^^^ error: compile_error macro braced works
65 "#,
66 );
67 }
68
69 #[test]
70 fn eager_macro_concat() {
71 check_diagnostics(
72 r#"
73//- /lib.rs crate:lib deps:core
74use core::{panic, concat};
75
76mod private {
77 pub use core::concat;
78}
79
80macro_rules! m {
81 () => {
82 panic!(concat!($crate::private::concat!("")));
83 };
84}
85
86fn f() {
87 m!();
88}
89
90//- /core.rs crate:core
91#[macro_export]
92#[rustc_builtin_macro]
93macro_rules! concat { () => {} }
94
95pub macro panic {
96 ($msg:expr) => (
97 $crate::panicking::panic_str($msg)
98 ),
99}
100 "#,
101 );
102 }
103
104 #[test]
105 fn include_macro_should_allow_empty_content() {
106 let mut config = DiagnosticsConfig::test_sample();
107
108 config.disabled.insert("unlinked-file".to_owned());
111
112 check_diagnostics_with_config(
113 config,
114 r#"
115//- /lib.rs
116#[rustc_builtin_macro]
117macro_rules! include { () => {} }
118
119include!("foo/bar.rs");
120//- /foo/bar.rs
121// empty
122"#,
123 );
124 }
125
126 #[test]
127 fn good_out_dir_diagnostic() {
128 check_diagnostics(
130 r#"
131#[rustc_builtin_macro]
132macro_rules! include { () => {} }
133#[rustc_builtin_macro]
134macro_rules! env { () => {} }
135#[rustc_builtin_macro]
136macro_rules! concat { () => {} }
137
138 include!(concat!(env!("OUT_DIR"), "/out.rs"));
139 //^^^^^^^^^ error: `OUT_DIR` not set, build scripts may have failed to run
140 //^^^^^^^^^^^^^^^ error: `OUT_DIR` not set, build scripts may have failed to run
141 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `OUT_DIR` not set, build scripts may have failed to run
142"#,
143 );
144 }
145
146 #[test]
147 fn register_tool() {
148 cov_mark::check!(register_tool);
149 check_diagnostics(
150 r#"
151#![register_tool(tool)]
152
153#[tool::path]
154struct S;
155"#,
156 );
157 }
159
160 #[test]
161 fn macro_diag_builtin() {
162 check_diagnostics(
163 r#"
164//- minicore: fmt
165#[rustc_builtin_macro]
166macro_rules! env {}
167
168#[rustc_builtin_macro]
169macro_rules! include {}
170
171#[rustc_builtin_macro]
172macro_rules! compile_error {}
173#[rustc_builtin_macro]
174macro_rules! concat {}
175
176fn main() {
177 // Test a handful of built-in (eager) macros:
178
179 include!(invalid);
180 //^^^^^^^ error: expected string literal
181 include!("does not exist");
182 //^^^^^^^^^^^^^^^^ error: failed to load file `does not exist`
183
184 include!(concat!("does ", "not ", "exist"));
185 //^^^^^^^^^^^^^^^^^^^^^^^^^^ error: failed to load file `does not exist`
186
187 env!(invalid);
188 //^^^^^^^ error: expected string literal
189
190 env!("OUT_DIR");
191 //^^^^^^^^^ error: `OUT_DIR` not set, build scripts may have failed to run
192
193 compile_error!("compile_error works");
194 //^^^^^^^^^^^^^ error: compile_error works
195
196 // Lazy:
197
198 format_args!();
199 //^^^^^^^^^^^ error: Syntax Error in Expansion: expected expression
200}
201"#,
202 );
203 }
204
205 #[test]
206 fn macro_rules_diag() {
207 check_diagnostics(
208 r#"
209macro_rules! m {
210 () => {};
211}
212fn f() {
213 m!();
214
215 m!(hi);
216 //^ error: leftover tokens
217}
218 "#,
219 );
220 }
221
222 #[test]
223 fn dollar_crate_in_builtin_macro() {
224 check_diagnostics(
225 r#"
226#[macro_export]
227#[rustc_builtin_macro]
228macro_rules! format_args {}
229
230#[macro_export]
231macro_rules! arg { () => {} }
232
233#[macro_export]
234macro_rules! outer {
235 () => {
236 $crate::format_args!( "", $crate::arg!(1) )
237 };
238}
239
240fn f() {
241 outer!();
242} //^^^^^^ error: leftover tokens
243 //^^^^^^ error: Syntax Error in Expansion: expected expression
244"#,
245 )
246 }
247
248 #[test]
249 fn def_diagnostic() {
250 check_diagnostics(
251 r#"
252macro_rules! foo {
253 //^^^ error: expected subtree
254 f => {};
255}
256
257fn f() {
258 foo!();
259 //^^^ error: macro definition has parse errors
260
261}
262"#,
263 )
264 }
265
266 #[test]
267 fn expansion_syntax_diagnostic() {
268 check_diagnostics(
269 r#"
270macro_rules! foo {
271 () => { struct; };
272}
273
274fn f() {
275 foo!();
276 //^^^ error: Syntax Error in Expansion: expected a name
277}
278"#,
279 )
280 }
281
282 #[test]
283 fn include_does_not_break_diagnostics() {
284 check_diagnostics(
285 r#"
286//- minicore: include
287//- /lib.rs crate:lib
288include!("include-me.rs");
289//- /include-me.rs
290/// long doc that pushes the diagnostic range beyond the first file's text length
291 #[err]
292//^^^^^^error: unresolved macro `err`
293mod prim_never {}
294"#,
295 );
296 }
297
298 #[test]
299 fn no_stack_overflow_for_missing_binding() {
300 check_diagnostics(
301 r#"
302#[macro_export]
303macro_rules! boom {
304 (
305 $($code:literal),+,
306 $(param: $param:expr,)?
307 ) => {{
308 let _ = $crate::boom!(@param $($param)*);
309 }};
310 (@param) => { () };
311 (@param $param:expr) => { $param };
312}
313
314fn it_works() {
315 // NOTE: there is an error, but RA crashes before showing it
316 boom!("RAND", param: c7.clone());
317 // ^^^^^ error: expected literal
318}
319
320 "#,
321 );
322 }
323}