diff options
Diffstat (limited to 'src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs')
-rw-r--r-- | src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs new file mode 100644 index 000000000..d6a66dc15 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs @@ -0,0 +1,218 @@ +use crate::{Diagnostic, DiagnosticsContext}; + +// Diagnostic: macro-error +// +// This diagnostic is shown for macro expansion errors. +pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic { + // Use more accurate position if available. + let display_range = d + .precise_location + .unwrap_or_else(|| ctx.sema.diagnostics_display_range(d.node.clone()).range); + + Diagnostic::new("macro-error", d.message.clone(), display_range).experimental() +} + +#[cfg(test)] +mod tests { + use crate::{ + tests::{check_diagnostics, check_diagnostics_with_config}, + DiagnosticsConfig, + }; + + #[test] + fn builtin_macro_fails_expansion() { + check_diagnostics( + r#" +#[rustc_builtin_macro] +macro_rules! include { () => {} } + +#[rustc_builtin_macro] +macro_rules! compile_error { () => {} } + + include!("doesntexist"); +//^^^^^^^ error: failed to load file `doesntexist` + + compile_error!("compile_error macro works"); +//^^^^^^^^^^^^^ error: compile_error macro works + "#, + ); + } + + #[test] + fn eager_macro_concat() { + // FIXME: this is incorrectly handling `$crate`, resulting in a wrong diagnostic. + // See: https://github.com/rust-lang/rust-analyzer/issues/10300 + + check_diagnostics( + r#" +//- /lib.rs crate:lib deps:core +use core::{panic, concat}; + +mod private { + pub use core::concat; +} + +macro_rules! m { + () => { + panic!(concat!($crate::private::concat!(""))); + }; +} + +fn f() { + m!(); + //^^^^ error: unresolved macro `$crate::private::concat!` +} + +//- /core.rs crate:core +#[macro_export] +#[rustc_builtin_macro] +macro_rules! concat { () => {} } + +pub macro panic { + ($msg:expr) => ( + $crate::panicking::panic_str($msg) + ), +} + "#, + ); + } + + #[test] + fn include_macro_should_allow_empty_content() { + let mut config = DiagnosticsConfig::default(); + + // FIXME: This is a false-positive, the file is actually linked in via + // `include!` macro + config.disabled.insert("unlinked-file".to_string()); + + check_diagnostics_with_config( + config, + 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")); +//^^^^^^^ error: `OUT_DIR` not set, enable "build scripts" to fix +"#, + ); + } + + #[test] + fn register_attr_and_tool() { + cov_mark::check!(register_attr); + cov_mark::check!(register_tool); + check_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); + //^^^^^^^ error: could not convert tokens + include!("does not exist"); + //^^^^^^^ error: failed to load file `does not exist` + + env!(invalid); + //^^^ error: could not convert tokens + + env!("OUT_DIR"); + //^^^ error: `OUT_DIR` not set, enable "build scripts" to fix + + compile_error!("compile_error works"); + //^^^^^^^^^^^^^ error: compile_error works + + // Lazy: + + format_args!(); + //^^^^^^^^^^^ error: no rule matches input tokens +} +"#, + ); + } + + #[test] + fn macro_rules_diag() { + check_diagnostics( + r#" +macro_rules! m { + () => {}; +} +fn f() { + m!(); + + m!(hi); + //^ error: 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!(); +} //^^^^^^^^ error: leftover tokens +"#, + ) + } +} |