Diagnose unresolved derive macros

This commit is contained in:
Jonas Schievink 2022-04-27 20:03:57 +02:00
parent 1ad500beb6
commit fa42888e27
6 changed files with 44 additions and 19 deletions

View File

@ -67,8 +67,9 @@ pub struct UnresolvedImport {
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct UnresolvedMacroCall { pub struct UnresolvedMacroCall {
pub macro_call: InFile<AstPtr<ast::MacroCall>>, pub macro_call: InFile<SyntaxNodePtr>,
pub path: ModPath, pub path: ModPath,
pub is_bang: bool,
} }
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]

View File

@ -701,8 +701,9 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag:
let node = ast.to_node(db.upcast()); let node = ast.to_node(db.upcast());
acc.push( acc.push(
UnresolvedMacroCall { UnresolvedMacroCall {
macro_call: InFile::new(ast.file_id, AstPtr::new(&node)), macro_call: InFile::new(node.file_id, SyntaxNodePtr::new(&node.value)),
path: path.clone(), path: path.clone(),
is_bang: matches!(ast, MacroCallKind::FnLike { .. }),
} }
.into(), .into(),
); );
@ -1170,7 +1171,12 @@ impl DefWithBody {
.into(), .into(),
), ),
BodyDiagnostic::UnresolvedMacroCall { node, path } => acc.push( BodyDiagnostic::UnresolvedMacroCall { node, path } => acc.push(
UnresolvedMacroCall { macro_call: node.clone(), path: path.clone() }.into(), UnresolvedMacroCall {
macro_call: node.clone().map(|ast_ptr| ast_ptr.into()),
path: path.clone(),
is_bang: true,
}
.into(),
), ),
} }
} }

View File

@ -813,12 +813,15 @@ impl Attr {
let paths = args let paths = args
.token_trees .token_trees
.split(|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. })))) .split(|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(Punct { char: ',', .. }))))
.map(|tts| { .filter_map(|tts| {
if tts.is_empty() {
return None;
}
let segments = tts.iter().filter_map(|tt| match tt { let segments = tts.iter().filter_map(|tt| match tt {
tt::TokenTree::Leaf(tt::Leaf::Ident(id)) => Some(id.as_name()), tt::TokenTree::Leaf(tt::Leaf::Ident(id)) => Some(id.as_name()),
_ => None, _ => None,
}); });
ModPath::from_segments(PathKind::Plain, segments) Some(ModPath::from_segments(PathKind::Plain, segments))
}); });
Some(paths) Some(paths)

View File

@ -1359,13 +1359,24 @@ impl DefCollector<'_> {
if let Err(UnresolvedMacro { path }) = macro_call_as_call_id { if let Err(UnresolvedMacro { path }) = macro_call_as_call_id {
self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call( self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
directive.module_id, directive.module_id,
ast_id.ast_id, MacroCallKind::FnLike { ast_id: ast_id.ast_id, expand_to: *expand_to },
path, path,
)); ));
} }
} }
MacroDirectiveKind::Derive { .. } | MacroDirectiveKind::Attr { .. } => { MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos } => {
// FIXME: we might want to diagnose this too self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
directive.module_id,
MacroCallKind::Derive {
ast_id: ast_id.ast_id,
derive_attr_index: derive_attr.ast_index,
derive_index: *derive_pos as u32,
},
ast_id.path.clone(),
));
}
MacroDirectiveKind::Attr { .. } => {
// FIXME: these should get diagnosed by `reseed_with_unresolved_attribute`
} }
} }
} }

View File

@ -25,7 +25,7 @@ pub enum DefDiagnosticKind {
UnresolvedProcMacro { ast: MacroCallKind }, UnresolvedProcMacro { ast: MacroCallKind },
UnresolvedMacroCall { ast: AstId<ast::MacroCall>, path: ModPath }, UnresolvedMacroCall { ast: MacroCallKind, path: ModPath },
MacroError { ast: MacroCallKind, message: String }, MacroError { ast: MacroCallKind, message: String },
@ -95,7 +95,7 @@ impl DefDiagnostic {
pub(super) fn unresolved_macro_call( pub(super) fn unresolved_macro_call(
container: LocalModuleId, container: LocalModuleId,
ast: AstId<ast::MacroCall>, ast: MacroCallKind,
path: ModPath, path: ModPath,
) -> Self { ) -> Self {
Self { in_module: container, kind: DefDiagnosticKind::UnresolvedMacroCall { ast, path } } Self { in_module: container, kind: DefDiagnosticKind::UnresolvedMacroCall { ast, path } }

View File

@ -1,5 +1,5 @@
use hir::{db::AstDatabase, InFile}; use hir::{db::AstDatabase, InFile};
use syntax::{AstNode, SyntaxNodePtr}; use syntax::{ast, AstNode, SyntaxNodePtr};
use crate::{Diagnostic, DiagnosticsContext}; use crate::{Diagnostic, DiagnosticsContext};
@ -12,19 +12,23 @@ pub(crate) fn unresolved_macro_call(
d: &hir::UnresolvedMacroCall, d: &hir::UnresolvedMacroCall,
) -> Diagnostic { ) -> Diagnostic {
let last_path_segment = ctx.sema.db.parse_or_expand(d.macro_call.file_id).and_then(|root| { let last_path_segment = ctx.sema.db.parse_or_expand(d.macro_call.file_id).and_then(|root| {
d.macro_call let node = d.macro_call.value.to_node(&root);
.value if let Some(macro_call) = ast::MacroCall::cast(node) {
.to_node(&root) macro_call
.path() .path()
.and_then(|it| it.segment()) .and_then(|it| it.segment())
.and_then(|it| it.name_ref()) .and_then(|it| it.name_ref())
.map(|it| InFile::new(d.macro_call.file_id, SyntaxNodePtr::new(it.syntax()))) .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 diagnostics = last_path_segment.unwrap_or_else(|| d.macro_call.clone().map(|it| it.into()));
let bang = if d.is_bang { "!" } else { "" };
Diagnostic::new( Diagnostic::new(
"unresolved-macro-call", "unresolved-macro-call",
format!("unresolved macro `{}!`", d.path), format!("unresolved macro `{}{}`", d.path, bang),
ctx.sema.diagnostics_display_range(diagnostics).range, ctx.sema.diagnostics_display_range(diagnostics).range,
) )
.experimental() .experimental()