internal: refactor unresolved macro call diagnostic

This commit is contained in:
Aleksey Kladov 2021-06-13 17:06:36 +03:00
parent 6d104de15a
commit fa9ed4e0ce
5 changed files with 94 additions and 95 deletions

View File

@ -17,7 +17,7 @@
};
macro_rules! diagnostics {
($($diag:ident),*) => {
($($diag:ident,)*) => {
pub enum AnyDiagnostic {$(
$diag(Box<$diag>),
)*}
@ -32,7 +32,13 @@ fn from(d: $diag) -> AnyDiagnostic {
};
}
diagnostics![UnresolvedModule, UnresolvedExternCrate, UnresolvedImport, MissingFields];
diagnostics![
UnresolvedModule,
UnresolvedExternCrate,
UnresolvedImport,
UnresolvedMacroCall,
MissingFields,
];
#[derive(Debug)]
pub struct UnresolvedModule {
@ -50,35 +56,12 @@ pub struct UnresolvedImport {
pub decl: InFile<AstPtr<ast::UseTree>>,
}
// Diagnostic: unresolved-macro-call
//
// This diagnostic is triggered if rust-analyzer is unable to resolve the path to a
// macro in a macro invocation.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct UnresolvedMacroCall {
pub file: HirFileId,
pub node: AstPtr<ast::MacroCall>,
pub macro_call: InFile<AstPtr<ast::MacroCall>>,
pub path: ModPath,
}
impl Diagnostic for UnresolvedMacroCall {
fn code(&self) -> DiagnosticCode {
DiagnosticCode("unresolved-macro-call")
}
fn message(&self) -> String {
format!("unresolved macro `{}!`", self.path)
}
fn display_source(&self) -> InFile<SyntaxNodePtr> {
InFile::new(self.file, self.node.clone().into())
}
fn as_any(&self) -> &(dyn Any + Send + 'static) {
self
}
fn is_experimental(&self) -> bool {
true
}
}
// Diagnostic: inactive-code
//
// This diagnostic is shown for code with inactive `#[cfg]` attributes.

View File

@ -580,11 +580,13 @@ pub fn diagnostics(
DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
let node = ast.to_node(db.upcast());
sink.push(UnresolvedMacroCall {
file: ast.file_id,
node: AstPtr::new(&node),
path: path.clone(),
});
acc.push(
UnresolvedMacroCall {
macro_call: InFile::new(ast.file_id, AstPtr::new(&node)),
path: path.clone(),
}
.into(),
);
}
DefDiagnosticKind::MacroError { ast, message } => {
@ -1060,13 +1062,9 @@ pub fn diagnostics(
precise_location: None,
macro_name: None,
}),
BodyDiagnostic::UnresolvedMacroCall { node, path } => {
sink.push(UnresolvedMacroCall {
file: node.file_id,
node: node.value.clone(),
path: path.clone(),
})
}
BodyDiagnostic::UnresolvedMacroCall { node, path } => acc.push(
UnresolvedMacroCall { macro_call: node.clone(), path: path.clone() }.into(),
),
}
}

View File

@ -54,37 +54,6 @@ fn inactive_via_cfg_attr() {
);
}
#[test]
fn unresolved_legacy_scope_macro() {
check_diagnostics(
r#"
//- /lib.rs
macro_rules! m { () => {} }
m!();
m2!();
//^^^^^^ UnresolvedMacroCall
"#,
);
}
#[test]
fn unresolved_module_scope_macro() {
check_diagnostics(
r#"
//- /lib.rs
mod mac {
#[macro_export]
macro_rules! m { () => {} }
}
self::m!();
self::m2!();
//^^^^^^^^^^^^ UnresolvedMacroCall
"#,
);
}
#[test]
fn builtin_macro_fails_expansion() {
check_diagnostics(

View File

@ -7,6 +7,7 @@
mod unresolved_module;
mod unresolved_extern_crate;
mod unresolved_import;
mod unresolved_macro_call;
mod missing_fields;
mod fixes;
@ -16,9 +17,8 @@
use std::cell::RefCell;
use hir::{
db::AstDatabase,
diagnostics::{AnyDiagnostic, Diagnostic as _, DiagnosticCode, DiagnosticSinkBuilder},
InFile, Semantics,
Semantics,
};
use ide_assists::AssistResolveStrategy;
use ide_db::{base_db::SourceDatabase, RootDatabase};
@ -203,20 +203,6 @@ pub(crate) fn diagnostics(
res.borrow_mut()
.push(Diagnostic::hint(display_range, d.message()).with_code(Some(d.code())));
})
.on::<hir::diagnostics::UnresolvedMacroCall, _>(|d| {
let last_path_segment = sema.db.parse_or_expand(d.file).and_then(|root| {
d.node
.to_node(&root)
.path()
.and_then(|it| it.segment())
.and_then(|it| it.name_ref())
.map(|it| InFile::new(d.file, SyntaxNodePtr::new(it.syntax())))
});
let diagnostics = last_path_segment.unwrap_or_else(|| d.display_source());
let display_range = sema.diagnostics_display_range(diagnostics).range;
res.borrow_mut()
.push(Diagnostic::error(display_range, d.message()).with_code(Some(d.code())));
})
.on::<hir::diagnostics::UnimplementedBuiltinMacro, _>(|d| {
let display_range = sema.diagnostics_display_range(d.display_source()).range;
res.borrow_mut()
@ -259,6 +245,7 @@ pub(crate) fn diagnostics(
AnyDiagnostic::UnresolvedModule(d) => unresolved_module::unresolved_module(&ctx, &d),
AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d),
AnyDiagnostic::UnresolvedImport(d) => unresolved_import::unresolved_import(&ctx, &d),
AnyDiagnostic::UnresolvedMacroCall(d) => unresolved_macro_call::unresolved_macro_call(&ctx, &d),
AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d),
};
if let Some(code) = d.code {
@ -480,16 +467,6 @@ pub(crate) fn check_diagnostics(ra_fixture: &str) {
assert_eq!(expected, actual);
}
#[test]
fn test_unresolved_macro_range() {
check_diagnostics(
r#"
foo::bar!(92);
//^^^ unresolved macro `foo::bar!`
"#,
);
}
#[test]
fn range_mapping_out_of_macros() {
// FIXME: this is very wrong, but somewhat tricky to fix.

View File

@ -0,0 +1,72 @@
use hir::{db::AstDatabase, InFile};
use syntax::{AstNode, SyntaxNodePtr};
use crate::diagnostics::{Diagnostic, DiagnosticsContext};
// Diagnostic: unresolved-macro-call
//
// This diagnostic is triggered if rust-analyzer is unable to resolve the path
// to a macro in a macro invocation.
pub(super) 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| {
d.macro_call
.value
.to_node(&root)
.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())))
});
let diagnostics = last_path_segment.unwrap_or_else(|| d.macro_call.clone().map(|it| it.into()));
Diagnostic::new(
"unresolved-macro-call",
format!("unresolved macro `{}!`", d.path),
ctx.sema.diagnostics_display_range(diagnostics).range,
)
.experimental()
}
#[cfg(test)]
mod tests {
use crate::diagnostics::tests::check_diagnostics;
#[test]
fn test_unresolved_macro_range() {
check_diagnostics(
r#"
foo::bar!(92);
//^^^ unresolved macro `foo::bar!`
"#,
);
}
#[test]
fn unresolved_legacy_scope_macro() {
check_diagnostics(
r#"
macro_rules! m { () => {} }
m!(); m2!();
//^^ unresolved macro `self::m2!`
"#,
);
}
#[test]
fn unresolved_module_scope_macro() {
check_diagnostics(
r#"
mod mac {
#[macro_export]
macro_rules! m { () => {} } }
self::m!(); self::m2!();
//^^ unresolved macro `self::m2!`
"#,
);
}
}