aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2020-11-26 19:09:54 +0000
committerJonas Schievink <[email protected]>2020-11-27 12:50:22 +0000
commit0432aa0ed7be3f41d41928499abc688a956214cf (patch)
tree64df76e5182412d9a95bc5e63ef3b1db03a5d430 /crates/hir_def
parent1b2652097183b0a285891c02eea8a7d2af03e4b3 (diff)
Publish diagnostics for macro expansion errors
Diffstat (limited to 'crates/hir_def')
-rw-r--r--crates/hir_def/src/diagnostics.rs62
-rw-r--r--crates/hir_def/src/nameres.rs52
-rw-r--r--crates/hir_def/src/nameres/collector.rs27
3 files changed, 137 insertions, 4 deletions
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)]
137pub struct UnresolvedProcMacro {
138 pub file: HirFileId,
139 pub node: SyntaxNodePtr,
140 pub macro_name: Option<String>,
141}
142
143impl 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)]
168pub struct MacroError {
169 pub file: HirFileId,
170 pub node: SyntaxNodePtr,
171 pub message: String,
172}
173
174impl 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
8use base_db::{CrateId, FileId, ProcMacroId}; 8use base_db::{CrateId, FileId, ProcMacroId};
9use cfg::{CfgExpr, CfgOptions}; 9use cfg::{CfgExpr, CfgOptions};
10use hir_expand::InFile;
11use hir_expand::{ 10use 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};
18use hir_expand::{InFile, MacroCallLoc};
19use rustc_hash::{FxHashMap, FxHashSet}; 19use rustc_hash::{FxHashMap, FxHashSet};
20use syntax::ast; 20use syntax::ast;
21use test_utils::mark; 21use 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 {