From 00303284b5cc3a82e32dc3ecbbcfeb2f99de6818 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 13 Jun 2021 18:41:04 +0300 Subject: internal: refactor macro error --- crates/hir/src/diagnostics.rs | 26 +--- crates/hir/src/lib.rs | 20 +-- crates/hir_def/src/body/tests.rs | 88 ------------- crates/hir_def/src/nameres/tests.rs | 1 - crates/hir_def/src/nameres/tests/diagnostics.rs | 76 ----------- crates/ide/src/diagnostics.rs | 2 + crates/ide/src/diagnostics/macro_error.rs | 163 ++++++++++++++++++++++++ 7 files changed, 178 insertions(+), 198 deletions(-) delete mode 100644 crates/hir_def/src/nameres/tests/diagnostics.rs create mode 100644 crates/ide/src/diagnostics/macro_error.rs diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 2039d2b43..28580eeb4 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -37,6 +37,7 @@ diagnostics![ UnresolvedImport, UnresolvedMacroCall, UnresolvedProcMacro, + MacroError, MissingFields, InactiveCode, ]; @@ -79,35 +80,12 @@ pub struct UnresolvedProcMacro { pub macro_name: Option, } -// Diagnostic: macro-error -// -// This diagnostic is shown for macro expansion errors. #[derive(Debug, Clone, Eq, PartialEq)] pub struct MacroError { - pub file: HirFileId, - pub node: SyntaxNodePtr, + pub node: InFile, pub message: String, } -impl Diagnostic for MacroError { - fn code(&self) -> DiagnosticCode { - DiagnosticCode("macro-error") - } - fn message(&self) -> String { - self.message.clone() - } - fn display_source(&self) -> InFile { - InFile::new(self.file, self.node.clone()) - } - fn as_any(&self) -> &(dyn Any + Send + 'static) { - self - } - fn is_experimental(&self) -> bool { - // Newly added and not very well-tested, might contain false positives. - true - } -} - #[derive(Debug)] pub struct UnimplementedBuiltinMacro { pub file: HirFileId, diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 87a3db946..d891d0ec1 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -587,19 +587,19 @@ impl Module { } DefDiagnosticKind::MacroError { ast, message } => { - let (file, ast) = match ast { + let node = match ast { MacroCallKind::FnLike { ast_id, .. } => { let node = ast_id.to_node(db.upcast()); - (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) + ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))) } MacroCallKind::Derive { ast_id, .. } | MacroCallKind::Attr { ast_id, .. } => { // FIXME: point to the attribute instead, this creates very large diagnostics let node = ast_id.to_node(db.upcast()); - (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) + ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))) } }; - sink.push(MacroError { file, node: ast, message: message.clone() }); + acc.push(MacroError { node, message: message.clone() }.into()); } DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => { @@ -1046,11 +1046,13 @@ impl Function { InactiveCode { node: node.clone(), cfg: cfg.clone(), opts: opts.clone() } .into(), ), - BodyDiagnostic::MacroError { node, message } => sink.push(MacroError { - file: node.file_id, - node: node.value.clone().into(), - message: message.to_string(), - }), + BodyDiagnostic::MacroError { node, message } => acc.push( + MacroError { + node: node.clone().map(|it| it.into()), + message: message.to_string(), + } + .into(), + ), BodyDiagnostic::UnresolvedProcMacro { node } => acc.push( UnresolvedProcMacro { node: node.clone().map(|it| it.into()), diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs index 075dcc6d2..0dccabcfd 100644 --- a/crates/hir_def/src/body/tests.rs +++ b/crates/hir_def/src/body/tests.rs @@ -88,67 +88,6 @@ mod m { ); } -#[test] -fn macro_diag_builtin() { - check_diagnostics( - r#" -#[rustc_builtin_macro] -macro_rules! env {} - -#[rustc_builtin_macro] -macro_rules! include {} - -#[rustc_builtin_macro] -macro_rules! compile_error {} - -#[rustc_builtin_macro] -macro_rules! format_args { - () => {} -} - -fn f() { - // Test a handful of built-in (eager) macros: - - include!(invalid); - //^^^^^^^^^^^^^^^^^ could not convert tokens - include!("does not exist"); - //^^^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `does not exist` - - env!(invalid); - //^^^^^^^^^^^^^ could not convert tokens - - env!("OUT_DIR"); - //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix - - compile_error!("compile_error works"); - //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works - - // Lazy: - - format_args!(); - //^^^^^^^^^^^^^^ no rule matches input tokens -} - "#, - ); -} - -#[test] -fn macro_rules_diag() { - check_diagnostics( - r#" -macro_rules! m { - () => {}; -} -fn f() { - m!(); - - m!(hi); - //^^^^^^ leftover tokens -} - "#, - ); -} - #[test] fn unresolved_macro_diag() { check_diagnostics( @@ -161,30 +100,3 @@ fn f() { ); } -#[test] -fn dollar_crate_in_builtin_macro() { - check_diagnostics( - r#" -#[macro_export] -#[rustc_builtin_macro] -macro_rules! format_args {} - -#[macro_export] -macro_rules! arg { - () => {} -} - -#[macro_export] -macro_rules! outer { - () => { - $crate::format_args!( "", $crate::arg!(1) ) - }; -} - -fn f() { - outer!(); - //^^^^^^^^ leftover tokens -} - "#, - ) -} diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs index 58c01354a..cf43f2a96 100644 --- a/crates/hir_def/src/nameres/tests.rs +++ b/crates/hir_def/src/nameres/tests.rs @@ -2,7 +2,6 @@ mod globs; mod incremental; mod macros; mod mod_resolution; -mod diagnostics; mod primitives; use std::sync::Arc; diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs deleted file mode 100644 index f1ee03d4d..000000000 --- a/crates/hir_def/src/nameres/tests/diagnostics.rs +++ /dev/null @@ -1,76 +0,0 @@ -use base_db::fixture::WithFixture; - -use crate::test_db::TestDB; - -fn check_diagnostics(ra_fixture: &str) { - let db: TestDB = TestDB::with_files(ra_fixture); - db.check_diagnostics(); -} - -fn check_no_diagnostics(ra_fixture: &str) { - let db: TestDB = TestDB::with_files(ra_fixture); - db.check_no_diagnostics(); -} - -#[test] -fn builtin_macro_fails_expansion() { - check_diagnostics( - r#" - //- /lib.rs - #[rustc_builtin_macro] - macro_rules! include { () => {} } - - include!("doesntexist"); - //^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `doesntexist` - "#, - ); -} - -#[test] -fn include_macro_should_allow_empty_content() { - check_no_diagnostics( - r#" - //- /lib.rs - #[rustc_builtin_macro] - macro_rules! include { () => {} } - - include!("bar.rs"); - //- /bar.rs - // empty - "#, - ); -} - -#[test] -fn good_out_dir_diagnostic() { - check_diagnostics( - r#" - #[rustc_builtin_macro] - macro_rules! include { () => {} } - #[rustc_builtin_macro] - macro_rules! env { () => {} } - #[rustc_builtin_macro] - macro_rules! concat { () => {} } - - include!(concat!(env!("OUT_DIR"), "/out.rs")); - //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix - "#, - ); -} - -#[test] -fn register_attr_and_tool() { - cov_mark::check!(register_attr); - cov_mark::check!(register_tool); - check_no_diagnostics( - r#" -#![register_tool(tool)] -#![register_attr(attr)] - -#[tool::path] -#[attr] -struct S; - "#, - ); - // NB: we don't currently emit diagnostics here -} diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index f7965326d..c257ea8e7 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs @@ -9,6 +9,7 @@ mod unresolved_extern_crate; mod unresolved_import; mod unresolved_macro_call; mod unresolved_proc_macro; +mod macro_error; mod inactive_code; mod missing_fields; @@ -229,6 +230,7 @@ pub(crate) fn diagnostics( AnyDiagnostic::UnresolvedMacroCall(d) => unresolved_macro_call::unresolved_macro_call(&ctx, &d), AnyDiagnostic::UnresolvedProcMacro(d) => unresolved_proc_macro::unresolved_proc_macro(&ctx, &d), AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d), + AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d), AnyDiagnostic::InactiveCode(d) => match inactive_code::inactive_code(&ctx, &d) { Some(it) => it, diff --git a/crates/ide/src/diagnostics/macro_error.rs b/crates/ide/src/diagnostics/macro_error.rs new file mode 100644 index 000000000..8cc8cfb48 --- /dev/null +++ b/crates/ide/src/diagnostics/macro_error.rs @@ -0,0 +1,163 @@ +use crate::diagnostics::{Diagnostic, DiagnosticsContext}; + +// Diagnostic: macro-error +// +// This diagnostic is shown for macro expansion errors. +pub(super) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic { + Diagnostic::new( + "macro-error", + d.message.clone(), + ctx.sema.diagnostics_display_range(d.node.clone()).range, + ) + .experimental() +} + +#[cfg(test)] +mod tests { + use crate::diagnostics::tests::{check_diagnostics, check_no_diagnostics}; + + #[test] + fn builtin_macro_fails_expansion() { + check_diagnostics( + r#" +#[rustc_builtin_macro] +macro_rules! include { () => {} } + + include!("doesntexist"); +//^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `doesntexist` + "#, + ); + } + + #[test] + fn include_macro_should_allow_empty_content() { + check_diagnostics( + r#" +//- /lib.rs +#[rustc_builtin_macro] +macro_rules! include { () => {} } + +include!("foo/bar.rs"); +//- /foo/bar.rs +// empty +"#, + ); + } + + #[test] + fn good_out_dir_diagnostic() { + check_diagnostics( + r#" +#[rustc_builtin_macro] +macro_rules! include { () => {} } +#[rustc_builtin_macro] +macro_rules! env { () => {} } +#[rustc_builtin_macro] +macro_rules! concat { () => {} } + + include!(concat!(env!("OUT_DIR"), "/out.rs")); +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix +"#, + ); + } + + #[test] + fn register_attr_and_tool() { + cov_mark::check!(register_attr); + cov_mark::check!(register_tool); + check_no_diagnostics( + r#" +#![register_tool(tool)] +#![register_attr(attr)] + +#[tool::path] +#[attr] +struct S; +"#, + ); + // NB: we don't currently emit diagnostics here + } + + #[test] + fn macro_diag_builtin() { + check_diagnostics( + r#" +#[rustc_builtin_macro] +macro_rules! env {} + +#[rustc_builtin_macro] +macro_rules! include {} + +#[rustc_builtin_macro] +macro_rules! compile_error {} + +#[rustc_builtin_macro] +macro_rules! format_args { () => {} } + +fn main() { + // Test a handful of built-in (eager) macros: + + include!(invalid); + //^^^^^^^^^^^^^^^^^ could not convert tokens + include!("does not exist"); + //^^^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `does not exist` + + env!(invalid); + //^^^^^^^^^^^^^ could not convert tokens + + env!("OUT_DIR"); + //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix + + compile_error!("compile_error works"); + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works + + // Lazy: + + format_args!(); + //^^^^^^^^^^^^^^ no rule matches input tokens +} +"#, + ); + } + + #[test] + fn macro_rules_diag() { + check_diagnostics( + r#" +macro_rules! m { + () => {}; +} +fn f() { + m!(); + + m!(hi); + //^^^^^^ leftover tokens +} + "#, + ); + } + #[test] + fn dollar_crate_in_builtin_macro() { + check_diagnostics( + r#" +#[macro_export] +#[rustc_builtin_macro] +macro_rules! format_args {} + +#[macro_export] +macro_rules! arg { () => {} } + +#[macro_export] +macro_rules! outer { + () => { + $crate::format_args!( "", $crate::arg!(1) ) + }; +} + +fn f() { + outer!(); +} //^^^^^^^^ leftover tokens +"#, + ) + } +} -- cgit v1.2.3