diff options
author | Aleksey Kladov <[email protected]> | 2021-06-13 16:41:04 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2021-06-13 16:41:04 +0100 |
commit | 00303284b5cc3a82e32dc3ecbbcfeb2f99de6818 (patch) | |
tree | 685e3f21289eaeb25df597413528f25c6239813f /crates | |
parent | 1e4aaee7bbc1d56698e70158aa35f578422623d9 (diff) |
internal: refactor macro error
Diffstat (limited to 'crates')
-rw-r--r-- | crates/hir/src/diagnostics.rs | 26 | ||||
-rw-r--r-- | crates/hir/src/lib.rs | 20 | ||||
-rw-r--r-- | crates/hir_def/src/body/tests.rs | 88 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests.rs | 1 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/diagnostics.rs | 76 | ||||
-rw-r--r-- | crates/ide/src/diagnostics.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/diagnostics/macro_error.rs | 163 |
7 files changed, 178 insertions, 198 deletions
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 2039d2b43..28580eeb4 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs | |||
@@ -37,6 +37,7 @@ diagnostics![ | |||
37 | UnresolvedImport, | 37 | UnresolvedImport, |
38 | UnresolvedMacroCall, | 38 | UnresolvedMacroCall, |
39 | UnresolvedProcMacro, | 39 | UnresolvedProcMacro, |
40 | MacroError, | ||
40 | MissingFields, | 41 | MissingFields, |
41 | InactiveCode, | 42 | InactiveCode, |
42 | ]; | 43 | ]; |
@@ -79,35 +80,12 @@ pub struct UnresolvedProcMacro { | |||
79 | pub macro_name: Option<String>, | 80 | pub macro_name: Option<String>, |
80 | } | 81 | } |
81 | 82 | ||
82 | // Diagnostic: macro-error | ||
83 | // | ||
84 | // This diagnostic is shown for macro expansion errors. | ||
85 | #[derive(Debug, Clone, Eq, PartialEq)] | 83 | #[derive(Debug, Clone, Eq, PartialEq)] |
86 | pub struct MacroError { | 84 | pub struct MacroError { |
87 | pub file: HirFileId, | 85 | pub node: InFile<SyntaxNodePtr>, |
88 | pub node: SyntaxNodePtr, | ||
89 | pub message: String, | 86 | pub message: String, |
90 | } | 87 | } |
91 | 88 | ||
92 | impl Diagnostic for MacroError { | ||
93 | fn code(&self) -> DiagnosticCode { | ||
94 | DiagnosticCode("macro-error") | ||
95 | } | ||
96 | fn message(&self) -> String { | ||
97 | self.message.clone() | ||
98 | } | ||
99 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
100 | InFile::new(self.file, self.node.clone()) | ||
101 | } | ||
102 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
103 | self | ||
104 | } | ||
105 | fn is_experimental(&self) -> bool { | ||
106 | // Newly added and not very well-tested, might contain false positives. | ||
107 | true | ||
108 | } | ||
109 | } | ||
110 | |||
111 | #[derive(Debug)] | 89 | #[derive(Debug)] |
112 | pub struct UnimplementedBuiltinMacro { | 90 | pub struct UnimplementedBuiltinMacro { |
113 | pub file: HirFileId, | 91 | pub file: HirFileId, |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 87a3db946..d891d0ec1 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -587,19 +587,19 @@ impl Module { | |||
587 | } | 587 | } |
588 | 588 | ||
589 | DefDiagnosticKind::MacroError { ast, message } => { | 589 | DefDiagnosticKind::MacroError { ast, message } => { |
590 | let (file, ast) = match ast { | 590 | let node = match ast { |
591 | MacroCallKind::FnLike { ast_id, .. } => { | 591 | MacroCallKind::FnLike { ast_id, .. } => { |
592 | let node = ast_id.to_node(db.upcast()); | 592 | let node = ast_id.to_node(db.upcast()); |
593 | (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) | 593 | ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))) |
594 | } | 594 | } |
595 | MacroCallKind::Derive { ast_id, .. } | 595 | MacroCallKind::Derive { ast_id, .. } |
596 | | MacroCallKind::Attr { ast_id, .. } => { | 596 | | MacroCallKind::Attr { ast_id, .. } => { |
597 | // FIXME: point to the attribute instead, this creates very large diagnostics | 597 | // FIXME: point to the attribute instead, this creates very large diagnostics |
598 | let node = ast_id.to_node(db.upcast()); | 598 | let node = ast_id.to_node(db.upcast()); |
599 | (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) | 599 | ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))) |
600 | } | 600 | } |
601 | }; | 601 | }; |
602 | sink.push(MacroError { file, node: ast, message: message.clone() }); | 602 | acc.push(MacroError { node, message: message.clone() }.into()); |
603 | } | 603 | } |
604 | 604 | ||
605 | DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => { | 605 | DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => { |
@@ -1046,11 +1046,13 @@ impl Function { | |||
1046 | InactiveCode { node: node.clone(), cfg: cfg.clone(), opts: opts.clone() } | 1046 | InactiveCode { node: node.clone(), cfg: cfg.clone(), opts: opts.clone() } |
1047 | .into(), | 1047 | .into(), |
1048 | ), | 1048 | ), |
1049 | BodyDiagnostic::MacroError { node, message } => sink.push(MacroError { | 1049 | BodyDiagnostic::MacroError { node, message } => acc.push( |
1050 | file: node.file_id, | 1050 | MacroError { |
1051 | node: node.value.clone().into(), | 1051 | node: node.clone().map(|it| it.into()), |
1052 | message: message.to_string(), | 1052 | message: message.to_string(), |
1053 | }), | 1053 | } |
1054 | .into(), | ||
1055 | ), | ||
1054 | BodyDiagnostic::UnresolvedProcMacro { node } => acc.push( | 1056 | BodyDiagnostic::UnresolvedProcMacro { node } => acc.push( |
1055 | UnresolvedProcMacro { | 1057 | UnresolvedProcMacro { |
1056 | node: node.clone().map(|it| it.into()), | 1058 | node: node.clone().map(|it| it.into()), |
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs index 075dcc6d2..0dccabcfd 100644 --- a/crates/hir_def/src/body/tests.rs +++ b/crates/hir_def/src/body/tests.rs | |||
@@ -89,67 +89,6 @@ mod m { | |||
89 | } | 89 | } |
90 | 90 | ||
91 | #[test] | 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 | } | ||
108 | |||
109 | fn f() { | ||
110 | // Test a handful of built-in (eager) macros: | ||
111 | |||
112 | include!(invalid); | ||
113 | //^^^^^^^^^^^^^^^^^ could not convert tokens | ||
114 | include!("does not exist"); | ||
115 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `does not exist` | ||
116 | |||
117 | env!(invalid); | ||
118 | //^^^^^^^^^^^^^ could not convert tokens | ||
119 | |||
120 | env!("OUT_DIR"); | ||
121 | //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix | ||
122 | |||
123 | compile_error!("compile_error works"); | ||
124 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works | ||
125 | |||
126 | // Lazy: | ||
127 | |||
128 | format_args!(); | ||
129 | //^^^^^^^^^^^^^^ no rule matches input tokens | ||
130 | } | ||
131 | "#, | ||
132 | ); | ||
133 | } | ||
134 | |||
135 | #[test] | ||
136 | fn macro_rules_diag() { | ||
137 | check_diagnostics( | ||
138 | r#" | ||
139 | macro_rules! m { | ||
140 | () => {}; | ||
141 | } | ||
142 | fn f() { | ||
143 | m!(); | ||
144 | |||
145 | m!(hi); | ||
146 | //^^^^^^ leftover tokens | ||
147 | } | ||
148 | "#, | ||
149 | ); | ||
150 | } | ||
151 | |||
152 | #[test] | ||
153 | fn unresolved_macro_diag() { | 92 | fn unresolved_macro_diag() { |
154 | check_diagnostics( | 93 | check_diagnostics( |
155 | r#" | 94 | r#" |
@@ -161,30 +100,3 @@ fn f() { | |||
161 | ); | 100 | ); |
162 | } | 101 | } |
163 | 102 | ||
164 | #[test] | ||
165 | fn dollar_crate_in_builtin_macro() { | ||
166 | check_diagnostics( | ||
167 | r#" | ||
168 | #[macro_export] | ||
169 | #[rustc_builtin_macro] | ||
170 | macro_rules! format_args {} | ||
171 | |||
172 | #[macro_export] | ||
173 | macro_rules! arg { | ||
174 | () => {} | ||
175 | } | ||
176 | |||
177 | #[macro_export] | ||
178 | macro_rules! outer { | ||
179 | () => { | ||
180 | $crate::format_args!( "", $crate::arg!(1) ) | ||
181 | }; | ||
182 | } | ||
183 | |||
184 | fn f() { | ||
185 | outer!(); | ||
186 | //^^^^^^^^ leftover tokens | ||
187 | } | ||
188 | "#, | ||
189 | ) | ||
190 | } | ||
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs index 58c01354a..cf43f2a96 100644 --- a/crates/hir_def/src/nameres/tests.rs +++ b/crates/hir_def/src/nameres/tests.rs | |||
@@ -2,7 +2,6 @@ mod globs; | |||
2 | mod incremental; | 2 | mod incremental; |
3 | mod macros; | 3 | mod macros; |
4 | mod mod_resolution; | 4 | mod mod_resolution; |
5 | mod diagnostics; | ||
6 | mod primitives; | 5 | mod primitives; |
7 | 6 | ||
8 | use std::sync::Arc; | 7 | use std::sync::Arc; |
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs deleted file mode 100644 index f1ee03d4d..000000000 --- a/crates/hir_def/src/nameres/tests/diagnostics.rs +++ /dev/null | |||
@@ -1,76 +0,0 @@ | |||
1 | use base_db::fixture::WithFixture; | ||
2 | |||
3 | use crate::test_db::TestDB; | ||
4 | |||
5 | fn check_diagnostics(ra_fixture: &str) { | ||
6 | let db: TestDB = TestDB::with_files(ra_fixture); | ||
7 | db.check_diagnostics(); | ||
8 | } | ||
9 | |||
10 | fn check_no_diagnostics(ra_fixture: &str) { | ||
11 | let db: TestDB = TestDB::with_files(ra_fixture); | ||
12 | db.check_no_diagnostics(); | ||
13 | } | ||
14 | |||
15 | #[test] | ||
16 | fn builtin_macro_fails_expansion() { | ||
17 | check_diagnostics( | ||
18 | r#" | ||
19 | //- /lib.rs | ||
20 | #[rustc_builtin_macro] | ||
21 | macro_rules! include { () => {} } | ||
22 | |||
23 | include!("doesntexist"); | ||
24 | //^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `doesntexist` | ||
25 | "#, | ||
26 | ); | ||
27 | } | ||
28 | |||
29 | #[test] | ||
30 | fn include_macro_should_allow_empty_content() { | ||
31 | check_no_diagnostics( | ||
32 | r#" | ||
33 | //- /lib.rs | ||
34 | #[rustc_builtin_macro] | ||
35 | macro_rules! include { () => {} } | ||
36 | |||
37 | include!("bar.rs"); | ||
38 | //- /bar.rs | ||
39 | // empty | ||
40 | "#, | ||
41 | ); | ||
42 | } | ||
43 | |||
44 | #[test] | ||
45 | fn good_out_dir_diagnostic() { | ||
46 | check_diagnostics( | ||
47 | r#" | ||
48 | #[rustc_builtin_macro] | ||
49 | macro_rules! include { () => {} } | ||
50 | #[rustc_builtin_macro] | ||
51 | macro_rules! env { () => {} } | ||
52 | #[rustc_builtin_macro] | ||
53 | macro_rules! concat { () => {} } | ||
54 | |||
55 | include!(concat!(env!("OUT_DIR"), "/out.rs")); | ||
56 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix | ||
57 | "#, | ||
58 | ); | ||
59 | } | ||
60 | |||
61 | #[test] | ||
62 | fn register_attr_and_tool() { | ||
63 | cov_mark::check!(register_attr); | ||
64 | cov_mark::check!(register_tool); | ||
65 | check_no_diagnostics( | ||
66 | r#" | ||
67 | #![register_tool(tool)] | ||
68 | #![register_attr(attr)] | ||
69 | |||
70 | #[tool::path] | ||
71 | #[attr] | ||
72 | struct S; | ||
73 | "#, | ||
74 | ); | ||
75 | // NB: we don't currently emit diagnostics here | ||
76 | } | ||
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index f7965326d..c257ea8e7 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -9,6 +9,7 @@ mod unresolved_extern_crate; | |||
9 | mod unresolved_import; | 9 | mod unresolved_import; |
10 | mod unresolved_macro_call; | 10 | mod unresolved_macro_call; |
11 | mod unresolved_proc_macro; | 11 | mod unresolved_proc_macro; |
12 | mod macro_error; | ||
12 | mod inactive_code; | 13 | mod inactive_code; |
13 | mod missing_fields; | 14 | mod missing_fields; |
14 | 15 | ||
@@ -229,6 +230,7 @@ pub(crate) fn diagnostics( | |||
229 | AnyDiagnostic::UnresolvedMacroCall(d) => unresolved_macro_call::unresolved_macro_call(&ctx, &d), | 230 | AnyDiagnostic::UnresolvedMacroCall(d) => unresolved_macro_call::unresolved_macro_call(&ctx, &d), |
230 | AnyDiagnostic::UnresolvedProcMacro(d) => unresolved_proc_macro::unresolved_proc_macro(&ctx, &d), | 231 | AnyDiagnostic::UnresolvedProcMacro(d) => unresolved_proc_macro::unresolved_proc_macro(&ctx, &d), |
231 | AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d), | 232 | AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d), |
233 | AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d), | ||
232 | 234 | ||
233 | AnyDiagnostic::InactiveCode(d) => match inactive_code::inactive_code(&ctx, &d) { | 235 | AnyDiagnostic::InactiveCode(d) => match inactive_code::inactive_code(&ctx, &d) { |
234 | Some(it) => it, | 236 | Some(it) => it, |
diff --git a/crates/ide/src/diagnostics/macro_error.rs b/crates/ide/src/diagnostics/macro_error.rs new file mode 100644 index 000000000..8cc8cfb48 --- /dev/null +++ b/crates/ide/src/diagnostics/macro_error.rs | |||
@@ -0,0 +1,163 @@ | |||
1 | use crate::diagnostics::{Diagnostic, DiagnosticsContext}; | ||
2 | |||
3 | // Diagnostic: macro-error | ||
4 | // | ||
5 | // This diagnostic is shown for macro expansion errors. | ||
6 | pub(super) 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::diagnostics::tests::{check_diagnostics, check_no_diagnostics}; | ||
18 | |||
19 | #[test] | ||
20 | fn builtin_macro_fails_expansion() { | ||
21 | check_diagnostics( | ||
22 | r#" | ||
23 | #[rustc_builtin_macro] | ||
24 | macro_rules! include { () => {} } | ||
25 | |||
26 | include!("doesntexist"); | ||
27 | //^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `doesntexist` | ||
28 | "#, | ||
29 | ); | ||
30 | } | ||
31 | |||
32 | #[test] | ||
33 | fn include_macro_should_allow_empty_content() { | ||
34 | check_diagnostics( | ||
35 | r#" | ||
36 | //- /lib.rs | ||
37 | #[rustc_builtin_macro] | ||
38 | macro_rules! include { () => {} } | ||
39 | |||
40 | include!("foo/bar.rs"); | ||
41 | //- /foo/bar.rs | ||
42 | // empty | ||
43 | "#, | ||
44 | ); | ||
45 | } | ||
46 | |||
47 | #[test] | ||
48 | fn good_out_dir_diagnostic() { | ||
49 | check_diagnostics( | ||
50 | r#" | ||
51 | #[rustc_builtin_macro] | ||
52 | macro_rules! include { () => {} } | ||
53 | #[rustc_builtin_macro] | ||
54 | macro_rules! env { () => {} } | ||
55 | #[rustc_builtin_macro] | ||
56 | macro_rules! concat { () => {} } | ||
57 | |||
58 | include!(concat!(env!("OUT_DIR"), "/out.rs")); | ||
59 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix | ||
60 | "#, | ||
61 | ); | ||
62 | } | ||
63 | |||
64 | #[test] | ||
65 | fn register_attr_and_tool() { | ||
66 | cov_mark::check!(register_attr); | ||
67 | cov_mark::check!(register_tool); | ||
68 | check_no_diagnostics( | ||
69 | r#" | ||
70 | #![register_tool(tool)] | ||
71 | #![register_attr(attr)] | ||
72 | |||
73 | #[tool::path] | ||
74 | #[attr] | ||
75 | struct S; | ||
76 | "#, | ||
77 | ); | ||
78 | // NB: we don't currently emit diagnostics here | ||
79 | } | ||
80 | |||
81 | #[test] | ||
82 | fn macro_diag_builtin() { | ||
83 | check_diagnostics( | ||
84 | r#" | ||
85 | #[rustc_builtin_macro] | ||
86 | macro_rules! env {} | ||
87 | |||
88 | #[rustc_builtin_macro] | ||
89 | macro_rules! include {} | ||
90 | |||
91 | #[rustc_builtin_macro] | ||
92 | macro_rules! compile_error {} | ||
93 | |||
94 | #[rustc_builtin_macro] | ||
95 | macro_rules! format_args { () => {} } | ||
96 | |||
97 | fn main() { | ||
98 | // Test a handful of built-in (eager) macros: | ||
99 | |||
100 | include!(invalid); | ||
101 | //^^^^^^^^^^^^^^^^^ could not convert tokens | ||
102 | include!("does not exist"); | ||
103 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `does not exist` | ||
104 | |||
105 | env!(invalid); | ||
106 | //^^^^^^^^^^^^^ could not convert tokens | ||
107 | |||
108 | env!("OUT_DIR"); | ||
109 | //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix | ||
110 | |||
111 | compile_error!("compile_error works"); | ||
112 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works | ||
113 | |||
114 | // Lazy: | ||
115 | |||
116 | format_args!(); | ||
117 | //^^^^^^^^^^^^^^ no rule matches input tokens | ||
118 | } | ||
119 | "#, | ||
120 | ); | ||
121 | } | ||
122 | |||
123 | #[test] | ||
124 | fn macro_rules_diag() { | ||
125 | check_diagnostics( | ||
126 | r#" | ||
127 | macro_rules! m { | ||
128 | () => {}; | ||
129 | } | ||
130 | fn f() { | ||
131 | m!(); | ||
132 | |||
133 | m!(hi); | ||
134 | //^^^^^^ leftover tokens | ||
135 | } | ||
136 | "#, | ||
137 | ); | ||
138 | } | ||
139 | #[test] | ||
140 | fn dollar_crate_in_builtin_macro() { | ||
141 | check_diagnostics( | ||
142 | r#" | ||
143 | #[macro_export] | ||
144 | #[rustc_builtin_macro] | ||
145 | macro_rules! format_args {} | ||
146 | |||
147 | #[macro_export] | ||
148 | macro_rules! arg { () => {} } | ||
149 | |||
150 | #[macro_export] | ||
151 | macro_rules! outer { | ||
152 | () => { | ||
153 | $crate::format_args!( "", $crate::arg!(1) ) | ||
154 | }; | ||
155 | } | ||
156 | |||
157 | fn f() { | ||
158 | outer!(); | ||
159 | } //^^^^^^^^ leftover tokens | ||
160 | "#, | ||
161 | ) | ||
162 | } | ||
163 | } | ||