• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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