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