Improve proc macro errors a bit

Distinguish between
 - there is no build data (for some reason?)
 - there is build data, but the cargo package didn't build a proc macro dylib
 - there is a proc macro dylib, but it didn't contain the proc macro we expected
 - the name did not resolve to any macro (this is now an
 unresolved_macro_call even for attributes)

I changed the handling of disabled attribute macro expansion to
immediately ignore the macro and report an unresolved_proc_macro,
because otherwise they would now result in loud unresolved_macro_call
errors. I hope this doesn't break anything.

Also try to improve error ranges for unresolved_macro_call / macro_error
by reusing the code for unresolved_proc_macro. It's not perfect but
probably better than before.
This commit is contained in:
Florian Diebold 2022-06-24 13:03:13 +02:00
parent 32b40ded0f
commit c80c34867f
10 changed files with 164 additions and 163 deletions

View file

@ -1,6 +1,3 @@
use hir::{db::AstDatabase, InFile};
use syntax::{ast, AstNode, SyntaxNodePtr};
use crate::{Diagnostic, DiagnosticsContext};
// Diagnostic: unresolved-macro-call
@ -11,25 +8,16 @@ 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()));
// Use more accurate position if available.
let display_range = d
.precise_location
.unwrap_or_else(|| ctx.sema.diagnostics_display_range(d.macro_call.clone()).range);
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,
display_range,
)
.experimental()
}