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