More accurately place proc-macro diagnostic

This commit is contained in:
Jonas Schievink 2020-11-27 16:29:40 +01:00
parent 0432aa0ed7
commit d171838d63
4 changed files with 49 additions and 9 deletions

View file

@ -6,7 +6,7 @@ use stdx::format_to;
use cfg::{CfgExpr, CfgOptions, DnfExpr}; use cfg::{CfgExpr, CfgOptions, DnfExpr};
use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink}; use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink};
use hir_expand::{HirFileId, InFile}; use hir_expand::{HirFileId, InFile};
use syntax::{ast, AstPtr, SyntaxNodePtr}; use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
use crate::{db::DefDatabase, DefWithBodyId}; use crate::{db::DefDatabase, DefWithBodyId};
@ -137,6 +137,9 @@ impl Diagnostic for InactiveCode {
pub struct UnresolvedProcMacro { pub struct UnresolvedProcMacro {
pub file: HirFileId, pub file: HirFileId,
pub node: SyntaxNodePtr, 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<TextRange>,
pub macro_name: Option<String>, pub macro_name: Option<String>,
} }

View file

@ -287,7 +287,8 @@ mod diagnostics {
use hir_expand::diagnostics::DiagnosticSink; use hir_expand::diagnostics::DiagnosticSink;
use hir_expand::hygiene::Hygiene; use hir_expand::hygiene::Hygiene;
use hir_expand::{InFile, MacroCallKind}; 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::path::ModPath;
use crate::{db::DefDatabase, diagnostics::*, nameres::LocalModuleId, AstId}; use crate::{db::DefDatabase, diagnostics::*, nameres::LocalModuleId, AstId};
@ -425,6 +426,7 @@ mod diagnostics {
} }
DiagnosticKind::UnresolvedProcMacro { ast } => { DiagnosticKind::UnresolvedProcMacro { ast } => {
let mut precise_location = None;
let (file, ast, name) = match ast { let (file, ast, name) = match ast {
MacroCallKind::FnLike(ast) => { MacroCallKind::FnLike(ast) => {
let node = ast.to_node(db.upcast()); let node = ast.to_node(db.upcast());
@ -432,14 +434,47 @@ mod diagnostics {
} }
MacroCallKind::Attr(ast, name) => { MacroCallKind::Attr(ast, name) => {
let node = ast.to_node(db.upcast()); 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, ast.file_id,
SyntaxNodePtr::from(AstPtr::new(&node)), 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 } => { DiagnosticKind::MacroError { ast, message } => {

View file

@ -143,11 +143,13 @@ pub(crate) fn diagnostics(
); );
}) })
.on::<hir::diagnostics::UnresolvedProcMacro, _>(|d| { .on::<hir::diagnostics::UnresolvedProcMacro, _>(|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 // FIXME: it would be nice to tell the user whether proc macros are currently disabled
res.borrow_mut().push( res.borrow_mut()
Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message()) .push(Diagnostic::hint(display_range, d.message()).with_code(Some(d.code())));
.with_code(Some(d.code())),
);
}) })
// Only collect experimental diagnostics when they're enabled. // Only collect experimental diagnostics when they're enabled.
.filter(|diag| !(diag.is_experimental() && config.disable_experimental)) .filter(|diag| !(diag.is_experimental() && config.disable_experimental))

View file

@ -18,7 +18,7 @@ This diagnostic is triggered if item name doesn't follow https://doc.rust-lang.o
=== macro-error === 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. This diagnostic is shown for macro expansion errors.