aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2021-06-13 16:41:04 +0100
committerAleksey Kladov <[email protected]>2021-06-13 16:41:04 +0100
commit00303284b5cc3a82e32dc3ecbbcfeb2f99de6818 (patch)
tree685e3f21289eaeb25df597413528f25c6239813f
parent1e4aaee7bbc1d56698e70158aa35f578422623d9 (diff)
internal: refactor macro error
-rw-r--r--crates/hir/src/diagnostics.rs26
-rw-r--r--crates/hir/src/lib.rs20
-rw-r--r--crates/hir_def/src/body/tests.rs88
-rw-r--r--crates/hir_def/src/nameres/tests.rs1
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs76
-rw-r--r--crates/ide/src/diagnostics.rs2
-rw-r--r--crates/ide/src/diagnostics/macro_error.rs163
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)]
86pub struct MacroError { 84pub 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
92impl 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)]
112pub struct UnimplementedBuiltinMacro { 90pub 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]
92fn macro_diag_builtin() {
93 check_diagnostics(
94 r#"
95#[rustc_builtin_macro]
96macro_rules! env {}
97
98#[rustc_builtin_macro]
99macro_rules! include {}
100
101#[rustc_builtin_macro]
102macro_rules! compile_error {}
103
104#[rustc_builtin_macro]
105macro_rules! format_args {
106 () => {}
107}
108
109fn 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]
136fn macro_rules_diag() {
137 check_diagnostics(
138 r#"
139macro_rules! m {
140 () => {};
141}
142fn f() {
143 m!();
144
145 m!(hi);
146 //^^^^^^ leftover tokens
147}
148 "#,
149 );
150}
151
152#[test]
153fn unresolved_macro_diag() { 92fn 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]
165fn dollar_crate_in_builtin_macro() {
166 check_diagnostics(
167 r#"
168#[macro_export]
169#[rustc_builtin_macro]
170macro_rules! format_args {}
171
172#[macro_export]
173macro_rules! arg {
174 () => {}
175}
176
177#[macro_export]
178macro_rules! outer {
179 () => {
180 $crate::format_args!( "", $crate::arg!(1) )
181 };
182}
183
184fn 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;
2mod incremental; 2mod incremental;
3mod macros; 3mod macros;
4mod mod_resolution; 4mod mod_resolution;
5mod diagnostics;
6mod primitives; 5mod primitives;
7 6
8use std::sync::Arc; 7use 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 @@
1use base_db::fixture::WithFixture;
2
3use crate::test_db::TestDB;
4
5fn check_diagnostics(ra_fixture: &str) {
6 let db: TestDB = TestDB::with_files(ra_fixture);
7 db.check_diagnostics();
8}
9
10fn check_no_diagnostics(ra_fixture: &str) {
11 let db: TestDB = TestDB::with_files(ra_fixture);
12 db.check_no_diagnostics();
13}
14
15#[test]
16fn 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]
30fn 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]
45fn 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]
62fn 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]
72struct 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;
9mod unresolved_import; 9mod unresolved_import;
10mod unresolved_macro_call; 10mod unresolved_macro_call;
11mod unresolved_proc_macro; 11mod unresolved_proc_macro;
12mod macro_error;
12mod inactive_code; 13mod inactive_code;
13mod missing_fields; 14mod 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 @@
1use crate::diagnostics::{Diagnostic, DiagnosticsContext};
2
3// Diagnostic: macro-error
4//
5// This diagnostic is shown for macro expansion errors.
6pub(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)]
16mod 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]
24macro_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]
38macro_rules! include { () => {} }
39
40include!("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]
52macro_rules! include { () => {} }
53#[rustc_builtin_macro]
54macro_rules! env { () => {} }
55#[rustc_builtin_macro]
56macro_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]
75struct 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]
86macro_rules! env {}
87
88#[rustc_builtin_macro]
89macro_rules! include {}
90
91#[rustc_builtin_macro]
92macro_rules! compile_error {}
93
94#[rustc_builtin_macro]
95macro_rules! format_args { () => {} }
96
97fn 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#"
127macro_rules! m {
128 () => {};
129}
130fn 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]
145macro_rules! format_args {}
146
147#[macro_export]
148macro_rules! arg { () => {} }
149
150#[macro_export]
151macro_rules! outer {
152 () => {
153 $crate::format_args!( "", $crate::arg!(1) )
154 };
155}
156
157fn f() {
158 outer!();
159} //^^^^^^^^ leftover tokens
160"#,
161 )
162 }
163}