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/ide/src/diagnostics.rs | 2 + crates/ide/src/diagnostics/macro_error.rs | 163 ++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 crates/ide/src/diagnostics/macro_error.rs (limited to 'crates/ide') 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