mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-29 06:23:25 +00:00
Diagnose unresolved derive macros
This commit is contained in:
parent
1ad500beb6
commit
fa42888e27
6 changed files with 44 additions and 19 deletions
|
@ -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)]
|
||||||
|
|
|
@ -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(),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 } }
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in a new issue