diff --git a/crates/hir_def/src/diagnostics.rs b/crates/hir_def/src/diagnostics.rs index dd06e3f200..c71266dc09 100644 --- a/crates/hir_def/src/diagnostics.rs +++ b/crates/hir_def/src/diagnostics.rs @@ -6,7 +6,7 @@ use stdx::format_to; use cfg::{CfgExpr, CfgOptions, DnfExpr}; use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink}; use hir_expand::{HirFileId, InFile}; -use syntax::{ast, AstPtr, SyntaxNodePtr}; +use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; use crate::{db::DefDatabase, DefWithBodyId}; @@ -137,6 +137,9 @@ impl Diagnostic for InactiveCode { pub struct UnresolvedProcMacro { pub file: HirFileId, pub node: SyntaxNodePtr, + /// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange` + /// to use instead. + pub precise_location: Option, pub macro_name: Option, } diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index 3d65a46bf7..ffd0381d43 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs @@ -287,7 +287,8 @@ mod diagnostics { use hir_expand::diagnostics::DiagnosticSink; use hir_expand::hygiene::Hygiene; use hir_expand::{InFile, MacroCallKind}; - use syntax::{ast, AstPtr, SyntaxNodePtr}; + use syntax::ast::AttrsOwner; + use syntax::{ast, AstNode, AstPtr, SyntaxKind, SyntaxNodePtr}; use crate::path::ModPath; use crate::{db::DefDatabase, diagnostics::*, nameres::LocalModuleId, AstId}; @@ -425,6 +426,7 @@ mod diagnostics { } DiagnosticKind::UnresolvedProcMacro { ast } => { + let mut precise_location = None; let (file, ast, name) = match ast { MacroCallKind::FnLike(ast) => { let node = ast.to_node(db.upcast()); @@ -432,14 +434,47 @@ mod diagnostics { } MacroCallKind::Attr(ast, name) => { let node = ast.to_node(db.upcast()); + + // Compute the precise location of the macro name's token in the derive + // list. + // FIXME: This does not handle paths to the macro, but neither does the + // rest of r-a. + let derive_attrs = + node.attrs().filter_map(|attr| match attr.as_simple_call() { + Some((name, args)) if name == "derive" => Some(args), + _ => None, + }); + 'outer: for attr in derive_attrs { + let tokens = + attr.syntax().children_with_tokens().filter_map(|elem| { + match elem { + syntax::NodeOrToken::Node(_) => None, + syntax::NodeOrToken::Token(tok) => Some(tok), + } + }); + for token in tokens { + if token.kind() == SyntaxKind::IDENT + && token.to_string() == *name + { + precise_location = Some(token.text_range()); + break 'outer; + } + } + } + ( ast.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), - Some(name.to_string()), + Some(name.clone()), ) } }; - sink.push(UnresolvedProcMacro { file, node: ast, macro_name: name }); + sink.push(UnresolvedProcMacro { + file, + node: ast, + precise_location, + macro_name: name, + }); } DiagnosticKind::MacroError { ast, message } => { diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 8b4ceb9a10..9d3d882895 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs @@ -143,11 +143,13 @@ pub(crate) fn diagnostics( ); }) .on::(|d| { + // Use more accurate position if available. + let display_range = + d.precise_location.unwrap_or_else(|| sema.diagnostics_display_range(d).range); + // FIXME: it would be nice to tell the user whether proc macros are currently disabled - res.borrow_mut().push( - Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message()) - .with_code(Some(d.code())), - ); + 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)) diff --git a/docs/user/generated_diagnostic.adoc b/docs/user/generated_diagnostic.adoc index 1dfba66703..ec8581a03c 100644 --- a/docs/user/generated_diagnostic.adoc +++ b/docs/user/generated_diagnostic.adoc @@ -18,7 +18,7 @@ This diagnostic is triggered if item name doesn't follow https://doc.rust-lang.o === macro-error -**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_def/src/diagnostics.rs#L164[diagnostics.rs] +**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_def/src/diagnostics.rs#L167[diagnostics.rs] This diagnostic is shown for macro expansion errors.