diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-06-13 16:46:09 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2021-06-13 16:46:09 +0100 |
commit | 7bff76d8ae1e8c3fbada1ade9ccf5111a1c0547e (patch) | |
tree | 1e85ed9c3fdf144469d9766c43c5362f5a31530b /crates/ide | |
parent | 3d8df2aef87bca7ec3f0994d799462f08d1ad449 (diff) | |
parent | 4af7a35197a1cb159458694e69e17bd83dc9edff (diff) |
Merge #9249
9249: internal: remove def-level diagnostics tests r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ide')
-rw-r--r-- | crates/ide/src/diagnostics.rs | 49 | ||||
-rw-r--r-- | crates/ide/src/diagnostics/inactive_code.rs | 117 | ||||
-rw-r--r-- | crates/ide/src/diagnostics/macro_error.rs | 163 | ||||
-rw-r--r-- | crates/ide/src/diagnostics/unresolved_macro_call.rs | 12 | ||||
-rw-r--r-- | crates/ide/src/diagnostics/unresolved_proc_macro.rs | 30 |
5 files changed, 344 insertions, 27 deletions
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 1a4800832..c257ea8e7 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -8,6 +8,9 @@ mod unresolved_module; | |||
8 | mod unresolved_extern_crate; | 8 | 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; | ||
12 | mod macro_error; | ||
13 | mod inactive_code; | ||
11 | mod missing_fields; | 14 | mod missing_fields; |
12 | 15 | ||
13 | mod fixes; | 16 | mod fixes; |
@@ -67,6 +70,11 @@ impl Diagnostic { | |||
67 | self | 70 | self |
68 | } | 71 | } |
69 | 72 | ||
73 | fn severity(mut self, severity: Severity) -> Diagnostic { | ||
74 | self.severity = severity; | ||
75 | self | ||
76 | } | ||
77 | |||
70 | fn error(range: TextRange, message: String) -> Self { | 78 | fn error(range: TextRange, message: String) -> Self { |
71 | Self { | 79 | Self { |
72 | message, | 80 | message, |
@@ -164,22 +172,6 @@ pub(crate) fn diagnostics( | |||
164 | .on::<hir::diagnostics::ReplaceFilterMapNextWithFindMap, _>(|d| { | 172 | .on::<hir::diagnostics::ReplaceFilterMapNextWithFindMap, _>(|d| { |
165 | res.borrow_mut().push(warning_with_fix(d, &sema, resolve)); | 173 | res.borrow_mut().push(warning_with_fix(d, &sema, resolve)); |
166 | }) | 174 | }) |
167 | .on::<hir::diagnostics::InactiveCode, _>(|d| { | ||
168 | // If there's inactive code somewhere in a macro, don't propagate to the call-site. | ||
169 | if d.display_source().file_id.expansion_info(db).is_some() { | ||
170 | return; | ||
171 | } | ||
172 | |||
173 | // Override severity and mark as unused. | ||
174 | res.borrow_mut().push( | ||
175 | Diagnostic::hint( | ||
176 | sema.diagnostics_display_range(d.display_source()).range, | ||
177 | d.message(), | ||
178 | ) | ||
179 | .with_unused(true) | ||
180 | .with_code(Some(d.code())), | ||
181 | ); | ||
182 | }) | ||
183 | .on::<UnlinkedFile, _>(|d| { | 175 | .on::<UnlinkedFile, _>(|d| { |
184 | // Limit diagnostic to the first few characters in the file. This matches how VS Code | 176 | // Limit diagnostic to the first few characters in the file. This matches how VS Code |
185 | // renders it with the full span, but on other editors, and is less invasive. | 177 | // renders it with the full span, but on other editors, and is less invasive. |
@@ -193,16 +185,6 @@ pub(crate) fn diagnostics( | |||
193 | .with_code(Some(d.code())), | 185 | .with_code(Some(d.code())), |
194 | ); | 186 | ); |
195 | }) | 187 | }) |
196 | .on::<hir::diagnostics::UnresolvedProcMacro, _>(|d| { | ||
197 | // Use more accurate position if available. | ||
198 | let display_range = d | ||
199 | .precise_location | ||
200 | .unwrap_or_else(|| sema.diagnostics_display_range(d.display_source()).range); | ||
201 | |||
202 | // FIXME: it would be nice to tell the user whether proc macros are currently disabled | ||
203 | res.borrow_mut() | ||
204 | .push(Diagnostic::hint(display_range, d.message()).with_code(Some(d.code()))); | ||
205 | }) | ||
206 | .on::<hir::diagnostics::UnimplementedBuiltinMacro, _>(|d| { | 188 | .on::<hir::diagnostics::UnimplementedBuiltinMacro, _>(|d| { |
207 | let display_range = sema.diagnostics_display_range(d.display_source()).range; | 189 | let display_range = sema.diagnostics_display_range(d.display_source()).range; |
208 | res.borrow_mut() | 190 | res.borrow_mut() |
@@ -246,7 +228,14 @@ pub(crate) fn diagnostics( | |||
246 | AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d), | 228 | AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d), |
247 | AnyDiagnostic::UnresolvedImport(d) => unresolved_import::unresolved_import(&ctx, &d), | 229 | AnyDiagnostic::UnresolvedImport(d) => unresolved_import::unresolved_import(&ctx, &d), |
248 | AnyDiagnostic::UnresolvedMacroCall(d) => unresolved_macro_call::unresolved_macro_call(&ctx, &d), | 230 | AnyDiagnostic::UnresolvedMacroCall(d) => unresolved_macro_call::unresolved_macro_call(&ctx, &d), |
231 | AnyDiagnostic::UnresolvedProcMacro(d) => unresolved_proc_macro::unresolved_proc_macro(&ctx, &d), | ||
249 | 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), | ||
234 | |||
235 | AnyDiagnostic::InactiveCode(d) => match inactive_code::inactive_code(&ctx, &d) { | ||
236 | Some(it) => it, | ||
237 | None => continue, | ||
238 | } | ||
250 | }; | 239 | }; |
251 | if let Some(code) = d.code { | 240 | if let Some(code) = d.code { |
252 | if ctx.config.disabled.contains(code.as_str()) { | 241 | if ctx.config.disabled.contains(code.as_str()) { |
@@ -451,7 +440,13 @@ mod tests { | |||
451 | expect.assert_debug_eq(&diagnostics) | 440 | expect.assert_debug_eq(&diagnostics) |
452 | } | 441 | } |
453 | 442 | ||
443 | #[track_caller] | ||
454 | pub(crate) fn check_diagnostics(ra_fixture: &str) { | 444 | pub(crate) fn check_diagnostics(ra_fixture: &str) { |
445 | check_diagnostics_with_inactive_code(ra_fixture, false) | ||
446 | } | ||
447 | |||
448 | #[track_caller] | ||
449 | pub(crate) fn check_diagnostics_with_inactive_code(ra_fixture: &str, with_inactive_code: bool) { | ||
455 | let (analysis, file_id) = fixture::file(ra_fixture); | 450 | let (analysis, file_id) = fixture::file(ra_fixture); |
456 | let diagnostics = analysis | 451 | let diagnostics = analysis |
457 | .diagnostics(&DiagnosticsConfig::default(), AssistResolveStrategy::All, file_id) | 452 | .diagnostics(&DiagnosticsConfig::default(), AssistResolveStrategy::All, file_id) |
@@ -460,7 +455,7 @@ mod tests { | |||
460 | let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); | 455 | let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); |
461 | let mut actual = diagnostics | 456 | let mut actual = diagnostics |
462 | .into_iter() | 457 | .into_iter() |
463 | .filter(|d| d.code != Some(DiagnosticCode("inactive-code"))) | 458 | .filter(|d| d.code != Some(DiagnosticCode("inactive-code")) || with_inactive_code) |
464 | .map(|d| (d.range, d.message)) | 459 | .map(|d| (d.range, d.message)) |
465 | .collect::<Vec<_>>(); | 460 | .collect::<Vec<_>>(); |
466 | actual.sort_by_key(|(range, _)| range.start()); | 461 | actual.sort_by_key(|(range, _)| range.start()); |
diff --git a/crates/ide/src/diagnostics/inactive_code.rs b/crates/ide/src/diagnostics/inactive_code.rs new file mode 100644 index 000000000..afe333204 --- /dev/null +++ b/crates/ide/src/diagnostics/inactive_code.rs | |||
@@ -0,0 +1,117 @@ | |||
1 | use cfg::DnfExpr; | ||
2 | use stdx::format_to; | ||
3 | |||
4 | use crate::{ | ||
5 | diagnostics::{Diagnostic, DiagnosticsContext}, | ||
6 | Severity, | ||
7 | }; | ||
8 | |||
9 | // Diagnostic: inactive-code | ||
10 | // | ||
11 | // This diagnostic is shown for code with inactive `#[cfg]` attributes. | ||
12 | pub(super) fn inactive_code( | ||
13 | ctx: &DiagnosticsContext<'_>, | ||
14 | d: &hir::InactiveCode, | ||
15 | ) -> Option<Diagnostic> { | ||
16 | // If there's inactive code somewhere in a macro, don't propagate to the call-site. | ||
17 | if d.node.file_id.expansion_info(ctx.sema.db).is_some() { | ||
18 | return None; | ||
19 | } | ||
20 | |||
21 | let inactive = DnfExpr::new(d.cfg.clone()).why_inactive(&d.opts); | ||
22 | let mut message = "code is inactive due to #[cfg] directives".to_string(); | ||
23 | |||
24 | if let Some(inactive) = inactive { | ||
25 | format_to!(message, ": {}", inactive); | ||
26 | } | ||
27 | |||
28 | let res = Diagnostic::new( | ||
29 | "inactive-code", | ||
30 | message, | ||
31 | ctx.sema.diagnostics_display_range(d.node.clone()).range, | ||
32 | ) | ||
33 | .severity(Severity::WeakWarning) | ||
34 | .with_unused(true); | ||
35 | Some(res) | ||
36 | } | ||
37 | |||
38 | #[cfg(test)] | ||
39 | mod tests { | ||
40 | use crate::diagnostics::tests::check_diagnostics_with_inactive_code; | ||
41 | |||
42 | #[test] | ||
43 | fn cfg_diagnostics() { | ||
44 | check_diagnostics_with_inactive_code( | ||
45 | r#" | ||
46 | fn f() { | ||
47 | // The three g̶e̶n̶d̶e̶r̶s̶ statements: | ||
48 | |||
49 | #[cfg(a)] fn f() {} // Item statement | ||
50 | //^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
51 | #[cfg(a)] {} // Expression statement | ||
52 | //^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
53 | #[cfg(a)] let x = 0; // let statement | ||
54 | //^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
55 | |||
56 | abc(#[cfg(a)] 0); | ||
57 | //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
58 | let x = Struct { | ||
59 | #[cfg(a)] f: 0, | ||
60 | //^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
61 | }; | ||
62 | match () { | ||
63 | () => (), | ||
64 | #[cfg(a)] () => (), | ||
65 | //^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
66 | } | ||
67 | |||
68 | #[cfg(a)] 0 // Trailing expression of block | ||
69 | //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled | ||
70 | } | ||
71 | "#, | ||
72 | true, | ||
73 | ); | ||
74 | } | ||
75 | |||
76 | #[test] | ||
77 | fn inactive_item() { | ||
78 | // Additional tests in `cfg` crate. This only tests disabled cfgs. | ||
79 | |||
80 | check_diagnostics_with_inactive_code( | ||
81 | r#" | ||
82 | #[cfg(no)] pub fn f() {} | ||
83 | //^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled | ||
84 | |||
85 | #[cfg(no)] #[cfg(no2)] mod m; | ||
86 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no and no2 are disabled | ||
87 | |||
88 | #[cfg(all(not(a), b))] enum E {} | ||
89 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: b is disabled | ||
90 | |||
91 | #[cfg(feature = "std")] use std; | ||
92 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: feature = "std" is disabled | ||
93 | "#, | ||
94 | true, | ||
95 | ); | ||
96 | } | ||
97 | |||
98 | /// Tests that `cfg` attributes behind `cfg_attr` is handled properly. | ||
99 | #[test] | ||
100 | fn inactive_via_cfg_attr() { | ||
101 | cov_mark::check!(cfg_attr_active); | ||
102 | check_diagnostics_with_inactive_code( | ||
103 | r#" | ||
104 | #[cfg_attr(not(never), cfg(no))] fn f() {} | ||
105 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled | ||
106 | |||
107 | #[cfg_attr(not(never), cfg(not(no)))] fn f() {} | ||
108 | |||
109 | #[cfg_attr(never, cfg(no))] fn g() {} | ||
110 | |||
111 | #[cfg_attr(not(never), inline, cfg(no))] fn h() {} | ||
112 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled | ||
113 | "#, | ||
114 | true, | ||
115 | ); | ||
116 | } | ||
117 | } | ||
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 | } | ||
diff --git a/crates/ide/src/diagnostics/unresolved_macro_call.rs b/crates/ide/src/diagnostics/unresolved_macro_call.rs index a3af332a4..15b6a2730 100644 --- a/crates/ide/src/diagnostics/unresolved_macro_call.rs +++ b/crates/ide/src/diagnostics/unresolved_macro_call.rs | |||
@@ -35,6 +35,18 @@ mod tests { | |||
35 | use crate::diagnostics::tests::check_diagnostics; | 35 | use crate::diagnostics::tests::check_diagnostics; |
36 | 36 | ||
37 | #[test] | 37 | #[test] |
38 | fn unresolved_macro_diag() { | ||
39 | check_diagnostics( | ||
40 | r#" | ||
41 | fn f() { | ||
42 | m!(); | ||
43 | } //^ unresolved macro `m!` | ||
44 | |||
45 | "#, | ||
46 | ); | ||
47 | } | ||
48 | |||
49 | #[test] | ||
38 | fn test_unresolved_macro_range() { | 50 | fn test_unresolved_macro_range() { |
39 | check_diagnostics( | 51 | check_diagnostics( |
40 | r#" | 52 | r#" |
diff --git a/crates/ide/src/diagnostics/unresolved_proc_macro.rs b/crates/ide/src/diagnostics/unresolved_proc_macro.rs new file mode 100644 index 000000000..3dc6ab451 --- /dev/null +++ b/crates/ide/src/diagnostics/unresolved_proc_macro.rs | |||
@@ -0,0 +1,30 @@ | |||
1 | use crate::{ | ||
2 | diagnostics::{Diagnostic, DiagnosticsContext}, | ||
3 | Severity, | ||
4 | }; | ||
5 | |||
6 | // Diagnostic: unresolved-proc-macro | ||
7 | // | ||
8 | // This diagnostic is shown when a procedural macro can not be found. This usually means that | ||
9 | // procedural macro support is simply disabled (and hence is only a weak hint instead of an error), | ||
10 | // but can also indicate project setup problems. | ||
11 | // | ||
12 | // If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the | ||
13 | // `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can | ||
14 | // enable support for procedural macros (see `rust-analyzer.procMacro.enable`). | ||
15 | pub(super) fn unresolved_proc_macro( | ||
16 | ctx: &DiagnosticsContext<'_>, | ||
17 | d: &hir::UnresolvedProcMacro, | ||
18 | ) -> Diagnostic { | ||
19 | // Use more accurate position if available. | ||
20 | let display_range = d | ||
21 | .precise_location | ||
22 | .unwrap_or_else(|| ctx.sema.diagnostics_display_range(d.node.clone()).range); | ||
23 | // FIXME: it would be nice to tell the user whether proc macros are currently disabled | ||
24 | let message = match &d.macro_name { | ||
25 | Some(name) => format!("proc macro `{}` not expanded", name), | ||
26 | None => "proc macro not expanded".to_string(), | ||
27 | }; | ||
28 | |||
29 | Diagnostic::new("unresolved-proc-macro", message, display_range).severity(Severity::WeakWarning) | ||
30 | } | ||