diff options
Diffstat (limited to 'crates/ide_diagnostics/src/handlers/macro_error.rs')
-rw-r--r-- | crates/ide_diagnostics/src/handlers/macro_error.rs | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/crates/ide_diagnostics/src/handlers/macro_error.rs b/crates/ide_diagnostics/src/handlers/macro_error.rs new file mode 100644 index 000000000..d4d928ad1 --- /dev/null +++ b/crates/ide_diagnostics/src/handlers/macro_error.rs | |||
@@ -0,0 +1,173 @@ | |||
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 | } | ||