Skip to content

Commit d171838

Browse files
More accurately place proc-macro diagnostic
1 parent 0432aa0 commit d171838

File tree

4 files changed

+49
-9
lines changed

4 files changed

+49
-9
lines changed

crates/hir_def/src/diagnostics.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use stdx::format_to;
66
use cfg::{CfgExpr, CfgOptions, DnfExpr};
77
use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink};
88
use hir_expand::{HirFileId, InFile};
9-
use syntax::{ast, AstPtr, SyntaxNodePtr};
9+
use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
1010

1111
use crate::{db::DefDatabase, DefWithBodyId};
1212

@@ -137,6 +137,9 @@ impl Diagnostic for InactiveCode {
137137
pub struct UnresolvedProcMacro {
138138
pub file: HirFileId,
139139
pub node: SyntaxNodePtr,
140+
/// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange`
141+
/// to use instead.
142+
pub precise_location: Option<TextRange>,
140143
pub macro_name: Option<String>,
141144
}
142145

crates/hir_def/src/nameres.rs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,8 @@ mod diagnostics {
287287
use hir_expand::diagnostics::DiagnosticSink;
288288
use hir_expand::hygiene::Hygiene;
289289
use hir_expand::{InFile, MacroCallKind};
290-
use syntax::{ast, AstPtr, SyntaxNodePtr};
290+
use syntax::ast::AttrsOwner;
291+
use syntax::{ast, AstNode, AstPtr, SyntaxKind, SyntaxNodePtr};
291292

292293
use crate::path::ModPath;
293294
use crate::{db::DefDatabase, diagnostics::*, nameres::LocalModuleId, AstId};
@@ -425,21 +426,55 @@ mod diagnostics {
425426
}
426427

427428
DiagnosticKind::UnresolvedProcMacro { ast } => {
429+
let mut precise_location = None;
428430
let (file, ast, name) = match ast {
429431
MacroCallKind::FnLike(ast) => {
430432
let node = ast.to_node(db.upcast());
431433
(ast.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None)
432434
}
433435
MacroCallKind::Attr(ast, name) => {
434436
let node = ast.to_node(db.upcast());
437+
438+
// Compute the precise location of the macro name's token in the derive
439+
// list.
440+
// FIXME: This does not handle paths to the macro, but neither does the
441+
// rest of r-a.
442+
let derive_attrs =
443+
node.attrs().filter_map(|attr| match attr.as_simple_call() {
444+
Some((name, args)) if name == "derive" => Some(args),
445+
_ => None,
446+
});
447+
'outer: for attr in derive_attrs {
448+
let tokens =
449+
attr.syntax().children_with_tokens().filter_map(|elem| {
450+
match elem {
451+
syntax::NodeOrToken::Node(_) => None,
452+
syntax::NodeOrToken::Token(tok) => Some(tok),
453+
}
454+
});
455+
for token in tokens {
456+
if token.kind() == SyntaxKind::IDENT
457+
&& token.to_string() == *name
458+
{
459+
precise_location = Some(token.text_range());
460+
break 'outer;
461+
}
462+
}
463+
}
464+
435465
(
436466
ast.file_id,
437467
SyntaxNodePtr::from(AstPtr::new(&node)),
438-
Some(name.to_string()),
468+
Some(name.clone()),
439469
)
440470
}
441471
};
442-
sink.push(UnresolvedProcMacro { file, node: ast, macro_name: name });
472+
sink.push(UnresolvedProcMacro {
473+
file,
474+
node: ast,
475+
precise_location,
476+
macro_name: name,
477+
});
443478
}
444479

445480
DiagnosticKind::MacroError { ast, message } => {

crates/ide/src/diagnostics.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,13 @@ pub(crate) fn diagnostics(
143143
);
144144
})
145145
.on::<hir::diagnostics::UnresolvedProcMacro, _>(|d| {
146+
// Use more accurate position if available.
147+
let display_range =
148+
d.precise_location.unwrap_or_else(|| sema.diagnostics_display_range(d).range);
149+
146150
// FIXME: it would be nice to tell the user whether proc macros are currently disabled
147-
res.borrow_mut().push(
148-
Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message())
149-
.with_code(Some(d.code())),
150-
);
151+
res.borrow_mut()
152+
.push(Diagnostic::hint(display_range, d.message()).with_code(Some(d.code())));
151153
})
152154
// Only collect experimental diagnostics when they're enabled.
153155
.filter(|diag| !(diag.is_experimental() && config.disable_experimental))

docs/user/generated_diagnostic.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ This diagnostic is triggered if item name doesn't follow https://doc.rust-lang.o
1818

1919

2020
=== macro-error
21-
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_def/src/diagnostics.rs#L164[diagnostics.rs]
21+
**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/hir_def/src/diagnostics.rs#L167[diagnostics.rs]
2222

2323
This diagnostic is shown for macro expansion errors.
2424

0 commit comments

Comments
 (0)