From cb5454db86bae1e97d86b05607b5c36a89fb749b Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 30 May 2021 04:19:47 +0200 Subject: Diagnose unimplemented built-in macros --- crates/hir/src/diagnostics.rs | 24 ++++++++++++++++ crates/hir/src/lib.rs | 12 ++++++-- crates/hir_def/src/nameres/collector.rs | 48 ++++++++++++++++++++----------- crates/hir_def/src/nameres/diagnostics.rs | 9 ++++++ crates/hir_def/src/test_db.rs | 7 +++++ crates/ide/src/diagnostics.rs | 5 ++++ 6 files changed, 87 insertions(+), 18 deletions(-) diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 22ec7c6ac..2cdbd172a 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -227,3 +227,27 @@ impl Diagnostic for MacroError { true } } + +#[derive(Debug)] +pub struct UnimplementedBuiltinMacro { + pub file: HirFileId, + pub node: SyntaxNodePtr, +} + +impl Diagnostic for UnimplementedBuiltinMacro { + fn code(&self) -> DiagnosticCode { + DiagnosticCode("unimplemented-builtin-macro") + } + + fn message(&self) -> String { + "unimplemented built-in macro".to_string() + } + + fn display_source(&self) -> InFile { + InFile::new(self.file, self.node.clone()) + } + + fn as_any(&self) -> &(dyn Any + Send + 'static) { + self + } +} diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 975ae4869..d3ef29db4 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -36,8 +36,8 @@ use std::{iter, sync::Arc}; use arrayvec::ArrayVec; use base_db::{CrateDisplayName, CrateId, Edition, FileId}; use diagnostics::{ - InactiveCode, MacroError, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, - UnresolvedModule, UnresolvedProcMacro, + InactiveCode, MacroError, UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, + UnresolvedMacroCall, UnresolvedModule, UnresolvedProcMacro, }; use either::Either; use hir_def::{ @@ -565,6 +565,14 @@ impl Module { }; sink.push(MacroError { file, node: ast, message: message.clone() }); } + + DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => { + let node = ast.to_node(db.upcast()); + // Must have a name, otherwise we wouldn't emit it. + let name = node.name().expect("unimplemented builtin macro with no name"); + let ptr = SyntaxNodePtr::from(AstPtr::new(&name)); + sink.push(UnimplementedBuiltinMacro { file: ast.file_id, node: ptr }); + } } } for decl in self.declarations(db) { diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index d9d6c91a8..50b2b0af4 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs @@ -1679,14 +1679,22 @@ impl ModCollector<'_, '_> { None => &mac.name, }; let krate = self.def_collector.def_map.krate; - if let Some(macro_id) = find_builtin_macro(name, krate, ast_id) { - self.def_collector.define_macro_rules( - self.module_id, - mac.name.clone(), - macro_id, - is_export, - ); - return; + match find_builtin_macro(name, krate, ast_id) { + Some(macro_id) => { + self.def_collector.define_macro_rules( + self.module_id, + mac.name.clone(), + macro_id, + is_export, + ); + return; + } + None => { + self.def_collector + .def_map + .diagnostics + .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id)); + } } } @@ -1715,15 +1723,23 @@ impl ModCollector<'_, '_> { let macro_id = find_builtin_macro(&mac.name, krate, ast_id) .or_else(|| find_builtin_derive(&mac.name, krate, ast_id)); - if let Some(macro_id) = macro_id { - self.def_collector.define_macro_def( - self.module_id, - mac.name.clone(), - macro_id, - &self.item_tree[mac.visibility], - ); + match macro_id { + Some(macro_id) => { + self.def_collector.define_macro_def( + self.module_id, + mac.name.clone(), + macro_id, + &self.item_tree[mac.visibility], + ); + return; + } + None => { + self.def_collector + .def_map + .diagnostics + .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id)); + } } - return; } // Case 2: normal `macro` diff --git a/crates/hir_def/src/nameres/diagnostics.rs b/crates/hir_def/src/nameres/diagnostics.rs index 57c36c3c6..95061f601 100644 --- a/crates/hir_def/src/nameres/diagnostics.rs +++ b/crates/hir_def/src/nameres/diagnostics.rs @@ -27,6 +27,8 @@ pub enum DefDiagnosticKind { UnresolvedMacroCall { ast: AstId, path: ModPath }, MacroError { ast: MacroCallKind, message: String }, + + UnimplementedBuiltinMacro { ast: AstId }, } #[derive(Debug, PartialEq, Eq)] @@ -93,4 +95,11 @@ impl DefDiagnostic { ) -> Self { Self { in_module: container, kind: DefDiagnosticKind::UnresolvedMacroCall { ast, path } } } + + pub(super) fn unimplemented_builtin_macro( + container: LocalModuleId, + ast: AstId, + ) -> Self { + Self { in_module: container, kind: DefDiagnosticKind::UnimplementedBuiltinMacro { ast } } + } } diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs index a9c1e13e2..e840fe5e8 100644 --- a/crates/hir_def/src/test_db.rs +++ b/crates/hir_def/src/test_db.rs @@ -298,6 +298,13 @@ impl TestDB { DefDiagnosticKind::MacroError { ast, message } => { (ast.to_node(self.upcast()), message.as_str()) } + DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => { + let node = ast.to_node(self.upcast()); + ( + InFile::new(ast.file_id, node.syntax().clone()), + "UnimplementedBuiltinMacro", + ) + } }; let frange = node.as_ref().original_file_range(self); diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 6cf5810fa..d5c954b8b 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs @@ -182,6 +182,11 @@ pub(crate) fn diagnostics( res.borrow_mut() .push(Diagnostic::error(display_range, d.message()).with_code(Some(d.code()))); }) + .on::(|d| { + let display_range = sema.diagnostics_display_range(d.display_source()).range; + res.borrow_mut() + .push(Diagnostic::hint(display_range, d.message()).with_code(Some(d.code()))); + }) // Only collect experimental diagnostics when they're enabled. .filter(|diag| !(diag.is_experimental() && config.disable_experimental)) .filter(|diag| !config.disabled.contains(diag.code().as_str())); -- cgit v1.2.3