Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs')
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs b/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs new file mode 100644 index 0000000000..831d082bc7 --- /dev/null +++ b/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs @@ -0,0 +1,88 @@ +use hir::{db::AstDatabase, InFile}; +use syntax::{ast, AstNode, SyntaxNodePtr}; + +use crate::{Diagnostic, DiagnosticsContext}; + +// Diagnostic: unresolved-macro-call +// +// This diagnostic is triggered if rust-analyzer is unable to resolve the path +// to a macro in a macro invocation. +pub(crate) fn unresolved_macro_call( + ctx: &DiagnosticsContext<'_>, + d: &hir::UnresolvedMacroCall, +) -> Diagnostic { + let last_path_segment = ctx.sema.db.parse_or_expand(d.macro_call.file_id).and_then(|root| { + let node = d.macro_call.value.to_node(&root); + if let Some(macro_call) = ast::MacroCall::cast(node) { + macro_call + .path() + .and_then(|it| it.segment()) + .and_then(|it| it.name_ref()) + .map(|it| InFile::new(d.macro_call.file_id, SyntaxNodePtr::new(it.syntax()))) + } else { + None + } + }); + let diagnostics = last_path_segment.unwrap_or_else(|| d.macro_call.clone().map(|it| it.into())); + + let bang = if d.is_bang { "!" } else { "" }; + Diagnostic::new( + "unresolved-macro-call", + format!("unresolved macro `{}{}`", d.path, bang), + ctx.sema.diagnostics_display_range(diagnostics).range, + ) + .experimental() +} + +#[cfg(test)] +mod tests { + use crate::tests::check_diagnostics; + + #[test] + fn unresolved_macro_diag() { + check_diagnostics( + r#" +fn f() { + m!(); +} //^ error: unresolved macro `m!` + +"#, + ); + } + + #[test] + fn test_unresolved_macro_range() { + check_diagnostics( + r#" +foo::bar!(92); + //^^^ error: unresolved macro `foo::bar!` +"#, + ); + } + + #[test] + fn unresolved_legacy_scope_macro() { + check_diagnostics( + r#" +macro_rules! m { () => {} } + +m!(); m2!(); + //^^ error: unresolved macro `m2!` +"#, + ); + } + + #[test] + fn unresolved_module_scope_macro() { + check_diagnostics( + r#" +mod mac { +#[macro_export] +macro_rules! m { () => {} } } + +self::m!(); self::m2!(); + //^^ error: unresolved macro `self::m2!` +"#, + ); + } +} |