]> git.lizzy.rs Git - rust.git/blob - crates/ide_diagnostics/src/handlers/macro_error.rs
Fix item-level lazy macro errors
[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 include_macro_should_allow_empty_content() {
43         let mut config = DiagnosticsConfig::default();
44
45         // FIXME: This is a false-positive, the file is actually linked in via
46         // `include!` macro
47         config.disabled.insert("unlinked-file".to_string());
48
49         check_diagnostics_with_config(
50             config,
51             r#"
52 //- /lib.rs
53 #[rustc_builtin_macro]
54 macro_rules! include { () => {} }
55
56 include!("foo/bar.rs");
57 //- /foo/bar.rs
58 // empty
59 "#,
60         );
61     }
62
63     #[test]
64     fn good_out_dir_diagnostic() {
65         check_diagnostics(
66             r#"
67 #[rustc_builtin_macro]
68 macro_rules! include { () => {} }
69 #[rustc_builtin_macro]
70 macro_rules! env { () => {} }
71 #[rustc_builtin_macro]
72 macro_rules! concat { () => {} }
73
74   include!(concat!(env!("OUT_DIR"), "/out.rs"));
75 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `OUT_DIR` not set, enable "run build scripts" to fix
76 "#,
77         );
78     }
79
80     #[test]
81     fn register_attr_and_tool() {
82         cov_mark::check!(register_attr);
83         cov_mark::check!(register_tool);
84         check_diagnostics(
85             r#"
86 #![register_tool(tool)]
87 #![register_attr(attr)]
88
89 #[tool::path]
90 #[attr]
91 struct S;
92 "#,
93         );
94         // NB: we don't currently emit diagnostics here
95     }
96
97     #[test]
98     fn macro_diag_builtin() {
99         check_diagnostics(
100             r#"
101 #[rustc_builtin_macro]
102 macro_rules! env {}
103
104 #[rustc_builtin_macro]
105 macro_rules! include {}
106
107 #[rustc_builtin_macro]
108 macro_rules! compile_error {}
109
110 #[rustc_builtin_macro]
111 macro_rules! format_args { () => {} }
112
113 fn main() {
114     // Test a handful of built-in (eager) macros:
115
116     include!(invalid);
117   //^^^^^^^^^^^^^^^^^ error: could not convert tokens
118     include!("does not exist");
119   //^^^^^^^^^^^^^^^^^^^^^^^^^^ error: failed to load file `does not exist`
120
121     env!(invalid);
122   //^^^^^^^^^^^^^ error: could not convert tokens
123
124     env!("OUT_DIR");
125   //^^^^^^^^^^^^^^^ error: `OUT_DIR` not set, enable "run build scripts" to fix
126
127     compile_error!("compile_error works");
128   //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: compile_error works
129
130     // Lazy:
131
132     format_args!();
133   //^^^^^^^^^^^^^^ error: no rule matches input tokens
134 }
135 "#,
136         );
137     }
138
139     #[test]
140     fn macro_rules_diag() {
141         check_diagnostics(
142             r#"
143 macro_rules! m {
144     () => {};
145 }
146 fn f() {
147     m!();
148
149     m!(hi);
150   //^^^^^^ error: leftover tokens
151 }
152       "#,
153         );
154     }
155     #[test]
156     fn dollar_crate_in_builtin_macro() {
157         check_diagnostics(
158             r#"
159 #[macro_export]
160 #[rustc_builtin_macro]
161 macro_rules! format_args {}
162
163 #[macro_export]
164 macro_rules! arg { () => {} }
165
166 #[macro_export]
167 macro_rules! outer {
168     () => {
169         $crate::format_args!( "", $crate::arg!(1) )
170     };
171 }
172
173 fn f() {
174     outer!();
175 } //^^^^^^^^ error: leftover tokens
176 "#,
177         )
178     }
179 }