diff options
-rw-r--r-- | crates/hir/src/diagnostics.rs | 2 | ||||
-rw-r--r-- | crates/hir_def/src/diagnostics.rs | 62 | ||||
-rw-r--r-- | crates/hir_def/src/nameres.rs | 52 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 27 | ||||
-rw-r--r-- | crates/hir_expand/src/db.rs | 9 | ||||
-rw-r--r-- | crates/hir_expand/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/diagnostics.rs | 7 | ||||
-rw-r--r-- | docs/user/generated_diagnostic.adoc | 14 |
8 files changed, 168 insertions, 7 deletions
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index d9ad8db6f..eaf1a14ec 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | pub use hir_def::diagnostics::{InactiveCode, UnresolvedModule}; | 2 | pub use hir_def::diagnostics::{InactiveCode, UnresolvedModule, UnresolvedProcMacro}; |
3 | pub use hir_expand::diagnostics::{ | 3 | pub use hir_expand::diagnostics::{ |
4 | Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder, | 4 | Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder, |
5 | }; | 5 | }; |
diff --git a/crates/hir_def/src/diagnostics.rs b/crates/hir_def/src/diagnostics.rs index b221b290c..dd06e3f20 100644 --- a/crates/hir_def/src/diagnostics.rs +++ b/crates/hir_def/src/diagnostics.rs | |||
@@ -127,3 +127,65 @@ impl Diagnostic for InactiveCode { | |||
127 | self | 127 | self |
128 | } | 128 | } |
129 | } | 129 | } |
130 | |||
131 | // Diagnostic: unresolved-proc-macro | ||
132 | // | ||
133 | // This diagnostic is shown when a procedural macro can not be found. This usually means that | ||
134 | // procedural macro support is simply disabled (and hence is only a weak hint instead of an error), | ||
135 | // but can also indicate project setup problems. | ||
136 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
137 | pub struct UnresolvedProcMacro { | ||
138 | pub file: HirFileId, | ||
139 | pub node: SyntaxNodePtr, | ||
140 | pub macro_name: Option<String>, | ||
141 | } | ||
142 | |||
143 | impl Diagnostic for UnresolvedProcMacro { | ||
144 | fn code(&self) -> DiagnosticCode { | ||
145 | DiagnosticCode("unresolved-proc-macro") | ||
146 | } | ||
147 | |||
148 | fn message(&self) -> String { | ||
149 | match &self.macro_name { | ||
150 | Some(name) => format!("proc macro `{}` not expanded", name), | ||
151 | None => "proc macro not expanded".to_string(), | ||
152 | } | ||
153 | } | ||
154 | |||
155 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
156 | InFile::new(self.file, self.node.clone()) | ||
157 | } | ||
158 | |||
159 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
160 | self | ||
161 | } | ||
162 | } | ||
163 | |||
164 | // Diagnostic: macro-error | ||
165 | // | ||
166 | // This diagnostic is shown for macro expansion errors. | ||
167 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
168 | pub struct MacroError { | ||
169 | pub file: HirFileId, | ||
170 | pub node: SyntaxNodePtr, | ||
171 | pub message: String, | ||
172 | } | ||
173 | |||
174 | impl Diagnostic for MacroError { | ||
175 | fn code(&self) -> DiagnosticCode { | ||
176 | DiagnosticCode("macro-error") | ||
177 | } | ||
178 | fn message(&self) -> String { | ||
179 | self.message.clone() | ||
180 | } | ||
181 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
182 | InFile::new(self.file, self.node.clone()) | ||
183 | } | ||
184 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
185 | self | ||
186 | } | ||
187 | fn is_experimental(&self) -> bool { | ||
188 | // Newly added and not very well-tested, might contain false positives. | ||
189 | true | ||
190 | } | ||
191 | } | ||
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index 202a7dcb6..3d65a46bf 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs | |||
@@ -286,8 +286,8 @@ mod diagnostics { | |||
286 | use cfg::{CfgExpr, CfgOptions}; | 286 | use cfg::{CfgExpr, CfgOptions}; |
287 | use hir_expand::diagnostics::DiagnosticSink; | 287 | use hir_expand::diagnostics::DiagnosticSink; |
288 | use hir_expand::hygiene::Hygiene; | 288 | use hir_expand::hygiene::Hygiene; |
289 | use hir_expand::InFile; | 289 | use hir_expand::{InFile, MacroCallKind}; |
290 | use syntax::{ast, AstPtr}; | 290 | use syntax::{ast, AstPtr, SyntaxNodePtr}; |
291 | 291 | ||
292 | use crate::path::ModPath; | 292 | use crate::path::ModPath; |
293 | use crate::{db::DefDatabase, diagnostics::*, nameres::LocalModuleId, AstId}; | 293 | use crate::{db::DefDatabase, diagnostics::*, nameres::LocalModuleId, AstId}; |
@@ -301,6 +301,10 @@ mod diagnostics { | |||
301 | UnresolvedImport { ast: AstId<ast::Use>, index: usize }, | 301 | UnresolvedImport { ast: AstId<ast::Use>, index: usize }, |
302 | 302 | ||
303 | UnconfiguredCode { ast: AstId<ast::Item>, cfg: CfgExpr, opts: CfgOptions }, | 303 | UnconfiguredCode { ast: AstId<ast::Item>, cfg: CfgExpr, opts: CfgOptions }, |
304 | |||
305 | UnresolvedProcMacro { ast: MacroCallKind }, | ||
306 | |||
307 | MacroError { ast: MacroCallKind, message: String }, | ||
304 | } | 308 | } |
305 | 309 | ||
306 | #[derive(Debug, PartialEq, Eq)] | 310 | #[derive(Debug, PartialEq, Eq)] |
@@ -348,6 +352,18 @@ mod diagnostics { | |||
348 | Self { in_module: container, kind: DiagnosticKind::UnconfiguredCode { ast, cfg, opts } } | 352 | Self { in_module: container, kind: DiagnosticKind::UnconfiguredCode { ast, cfg, opts } } |
349 | } | 353 | } |
350 | 354 | ||
355 | pub(super) fn unresolved_proc_macro(container: LocalModuleId, ast: MacroCallKind) -> Self { | ||
356 | Self { in_module: container, kind: DiagnosticKind::UnresolvedProcMacro { ast } } | ||
357 | } | ||
358 | |||
359 | pub(super) fn macro_error( | ||
360 | container: LocalModuleId, | ||
361 | ast: MacroCallKind, | ||
362 | message: String, | ||
363 | ) -> Self { | ||
364 | Self { in_module: container, kind: DiagnosticKind::MacroError { ast, message } } | ||
365 | } | ||
366 | |||
351 | pub(super) fn add_to( | 367 | pub(super) fn add_to( |
352 | &self, | 368 | &self, |
353 | db: &dyn DefDatabase, | 369 | db: &dyn DefDatabase, |
@@ -407,6 +423,38 @@ mod diagnostics { | |||
407 | opts: opts.clone(), | 423 | opts: opts.clone(), |
408 | }); | 424 | }); |
409 | } | 425 | } |
426 | |||
427 | DiagnosticKind::UnresolvedProcMacro { ast } => { | ||
428 | let (file, ast, name) = match ast { | ||
429 | MacroCallKind::FnLike(ast) => { | ||
430 | let node = ast.to_node(db.upcast()); | ||
431 | (ast.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None) | ||
432 | } | ||
433 | MacroCallKind::Attr(ast, name) => { | ||
434 | let node = ast.to_node(db.upcast()); | ||
435 | ( | ||
436 | ast.file_id, | ||
437 | SyntaxNodePtr::from(AstPtr::new(&node)), | ||
438 | Some(name.to_string()), | ||
439 | ) | ||
440 | } | ||
441 | }; | ||
442 | sink.push(UnresolvedProcMacro { file, node: ast, macro_name: name }); | ||
443 | } | ||
444 | |||
445 | DiagnosticKind::MacroError { ast, message } => { | ||
446 | let (file, ast) = match ast { | ||
447 | MacroCallKind::FnLike(ast) => { | ||
448 | let node = ast.to_node(db.upcast()); | ||
449 | (ast.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) | ||
450 | } | ||
451 | MacroCallKind::Attr(ast, _) => { | ||
452 | let node = ast.to_node(db.upcast()); | ||
453 | (ast.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) | ||
454 | } | ||
455 | }; | ||
456 | sink.push(MacroError { file, node: ast, message: message.clone() }); | ||
457 | } | ||
410 | } | 458 | } |
411 | } | 459 | } |
412 | } | 460 | } |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 5ed9073e0..19cd713ba 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -7,7 +7,6 @@ use std::iter; | |||
7 | 7 | ||
8 | use base_db::{CrateId, FileId, ProcMacroId}; | 8 | use base_db::{CrateId, FileId, ProcMacroId}; |
9 | use cfg::{CfgExpr, CfgOptions}; | 9 | use cfg::{CfgExpr, CfgOptions}; |
10 | use hir_expand::InFile; | ||
11 | use hir_expand::{ | 10 | use hir_expand::{ |
12 | ast_id_map::FileAstId, | 11 | ast_id_map::FileAstId, |
13 | builtin_derive::find_builtin_derive, | 12 | builtin_derive::find_builtin_derive, |
@@ -16,6 +15,7 @@ use hir_expand::{ | |||
16 | proc_macro::ProcMacroExpander, | 15 | proc_macro::ProcMacroExpander, |
17 | HirFileId, MacroCallId, MacroDefId, MacroDefKind, | 16 | HirFileId, MacroCallId, MacroDefId, MacroDefKind, |
18 | }; | 17 | }; |
18 | use hir_expand::{InFile, MacroCallLoc}; | ||
19 | use rustc_hash::{FxHashMap, FxHashSet}; | 19 | use rustc_hash::{FxHashMap, FxHashSet}; |
20 | use syntax::ast; | 20 | use syntax::ast; |
21 | use test_utils::mark; | 21 | use test_utils::mark; |
@@ -812,7 +812,30 @@ impl DefCollector<'_> { | |||
812 | log::warn!("macro expansion is too deep"); | 812 | log::warn!("macro expansion is too deep"); |
813 | return; | 813 | return; |
814 | } | 814 | } |
815 | let file_id: HirFileId = macro_call_id.as_file(); | 815 | let file_id = macro_call_id.as_file(); |
816 | |||
817 | // First, fetch the raw expansion result for purposes of error reporting. This goes through | ||
818 | // `macro_expand_error` to avoid depending on the full expansion result (to improve | ||
819 | // incrementality). | ||
820 | let err = self.db.macro_expand_error(macro_call_id); | ||
821 | if let Some(err) = err { | ||
822 | if let MacroCallId::LazyMacro(id) = macro_call_id { | ||
823 | let loc: MacroCallLoc = self.db.lookup_intern_macro(id); | ||
824 | |||
825 | let diag = match err { | ||
826 | hir_expand::ExpandError::UnresolvedProcMacro => { | ||
827 | // Missing proc macros are non-fatal, so they are handled specially. | ||
828 | DefDiagnostic::unresolved_proc_macro(module_id, loc.kind) | ||
829 | } | ||
830 | _ => DefDiagnostic::macro_error(module_id, loc.kind, err.to_string()), | ||
831 | }; | ||
832 | |||
833 | self.def_map.diagnostics.push(diag); | ||
834 | } | ||
835 | // FIXME: Handle eager macros. | ||
836 | } | ||
837 | |||
838 | // Then, fetch and process the item tree. This will reuse the expansion result from above. | ||
816 | let item_tree = self.db.item_tree(file_id); | 839 | let item_tree = self.db.item_tree(file_id); |
817 | let mod_dir = self.mod_dirs[&module_id].clone(); | 840 | let mod_dir = self.mod_dirs[&module_id].clone(); |
818 | ModCollector { | 841 | ModCollector { |
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 46ebdbc74..7ea1c6301 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use base_db::{salsa, SourceDatabase}; | 5 | use base_db::{salsa, SourceDatabase}; |
6 | use mbe::{ExpandResult, MacroRules}; | 6 | use mbe::{ExpandError, ExpandResult, MacroRules}; |
7 | use parser::FragmentKind; | 7 | use parser::FragmentKind; |
8 | use syntax::{algo::diff, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode}; | 8 | use syntax::{algo::diff, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode}; |
9 | 9 | ||
@@ -81,6 +81,9 @@ pub trait AstDatabase: SourceDatabase { | |||
81 | ) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>>; | 81 | ) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>>; |
82 | fn macro_expand(&self, macro_call: MacroCallId) -> ExpandResult<Option<Arc<tt::Subtree>>>; | 82 | fn macro_expand(&self, macro_call: MacroCallId) -> ExpandResult<Option<Arc<tt::Subtree>>>; |
83 | 83 | ||
84 | /// Firewall query that returns the error from the `macro_expand` query. | ||
85 | fn macro_expand_error(&self, macro_call: MacroCallId) -> Option<ExpandError>; | ||
86 | |||
84 | #[salsa::interned] | 87 | #[salsa::interned] |
85 | fn intern_eager_expansion(&self, eager: EagerCallLoc) -> EagerMacroId; | 88 | fn intern_eager_expansion(&self, eager: EagerCallLoc) -> EagerMacroId; |
86 | 89 | ||
@@ -171,6 +174,10 @@ fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<Option<Ar | |||
171 | macro_expand_with_arg(db, id, None) | 174 | macro_expand_with_arg(db, id, None) |
172 | } | 175 | } |
173 | 176 | ||
177 | fn macro_expand_error(db: &dyn AstDatabase, macro_call: MacroCallId) -> Option<ExpandError> { | ||
178 | db.macro_expand(macro_call).err | ||
179 | } | ||
180 | |||
174 | fn expander(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { | 181 | fn expander(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { |
175 | let lazy_id = match id { | 182 | let lazy_id = match id { |
176 | MacroCallId::LazyMacro(id) => id, | 183 | MacroCallId::LazyMacro(id) => id, |
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index d5ba691b7..6dad2507b 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs | |||
@@ -255,7 +255,7 @@ pub enum MacroDefKind { | |||
255 | pub struct MacroCallLoc { | 255 | pub struct MacroCallLoc { |
256 | pub(crate) def: MacroDefId, | 256 | pub(crate) def: MacroDefId, |
257 | pub(crate) krate: CrateId, | 257 | pub(crate) krate: CrateId, |
258 | pub(crate) kind: MacroCallKind, | 258 | pub kind: MacroCallKind, |
259 | } | 259 | } |
260 | 260 | ||
261 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 261 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 3df73ed4f..8b4ceb9a1 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -142,6 +142,13 @@ pub(crate) fn diagnostics( | |||
142 | .with_code(Some(d.code())), | 142 | .with_code(Some(d.code())), |
143 | ); | 143 | ); |
144 | }) | 144 | }) |
145 | .on::<hir::diagnostics::UnresolvedProcMacro, _>(|d| { | ||
146 | // FIXME: it would be nice to tell the user whether proc macros are currently disabled | ||
147 | res.borrow_mut().push( | ||
148 | Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message()) | ||
149 | .with_code(Some(d.code())), | ||
150 | ); | ||
151 | }) | ||
145 | // Only collect experimental diagnostics when they're enabled. | 152 | // Only collect experimental diagnostics when they're enabled. |
146 | .filter(|diag| !(diag.is_experimental() && config.disable_experimental)) | 153 | .filter(|diag| !(diag.is_experimental() && config.disable_experimental)) |
147 | .filter(|diag| !config.disabled.contains(diag.code().as_str())); | 154 | .filter(|diag| !config.disabled.contains(diag.code().as_str())); |
diff --git a/docs/user/generated_diagnostic.adoc b/docs/user/generated_diagnostic.adoc index 34c4f98a3..1dfba6670 100644 --- a/docs/user/generated_diagnostic.adoc +++ b/docs/user/generated_diagnostic.adoc | |||
@@ -17,6 +17,12 @@ This diagnostic is shown for code with inactive `#[cfg]` attributes. | |||
17 | This diagnostic is triggered if item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention]. | 17 | This diagnostic is triggered if item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention]. |
18 | 18 | ||
19 | 19 | ||
20 | === macro-error | ||
21 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_def/src/diagnostics.rs#L164[diagnostics.rs] | ||
22 | |||
23 | This diagnostic is shown for macro expansion errors. | ||
24 | |||
25 | |||
20 | === mismatched-arg-count | 26 | === mismatched-arg-count |
21 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_ty/src/diagnostics.rs#L267[diagnostics.rs] | 27 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_ty/src/diagnostics.rs#L267[diagnostics.rs] |
22 | 28 | ||
@@ -103,3 +109,11 @@ This diagnostic is triggered if rust-analyzer is unable to discover imported mod | |||
103 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_def/src/diagnostics.rs#L18[diagnostics.rs] | 109 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_def/src/diagnostics.rs#L18[diagnostics.rs] |
104 | 110 | ||
105 | This diagnostic is triggered if rust-analyzer is unable to discover referred module. | 111 | This diagnostic is triggered if rust-analyzer is unable to discover referred module. |
112 | |||
113 | |||
114 | === unresolved-proc-macro | ||
115 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_def/src/diagnostics.rs#L131[diagnostics.rs] | ||
116 | |||
117 | This diagnostic is shown when a procedural macro can not be found. This usually means that | ||
118 | procedural macro support is simply disabled (and hence is only a weak hint instead of an error), | ||
119 | but can also indicate project setup problems. | ||