rust/crates/ide-diagnostics/src/handlers/macro_error.rs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

261 lines
5.3 KiB
Rust
Raw Normal View History

use crate::{Diagnostic, DiagnosticsContext};
2021-06-13 10:41:04 -05:00
// Diagnostic: macro-error
//
// This diagnostic is shown for macro expansion errors.
2021-06-14 11:32:39 -05:00
pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic {
// Use more accurate position if available.
let display_range = ctx.resolve_precise_location(&d.node, d.precise_location);
Diagnostic::new("macro-error", d.message.clone(), display_range).experimental()
2021-06-13 10:41:04 -05:00
}
// Diagnostic: macro-error
//
// This diagnostic is shown for macro expansion errors.
pub(crate) fn macro_def_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroDefError) -> Diagnostic {
// Use more accurate position if available.
let display_range =
ctx.resolve_precise_location(&d.node.clone().map(|it| it.syntax_node_ptr()), d.name);
Diagnostic::new("macro-def-error", d.message.clone(), display_range).experimental()
}
2021-06-13 10:41:04 -05:00
#[cfg(test)]
mod tests {
use crate::{
tests::{check_diagnostics, check_diagnostics_with_config},
DiagnosticsConfig,
};
2021-06-13 10:41:04 -05:00
#[test]
fn builtin_macro_fails_expansion() {
check_diagnostics(
r#"
#[rustc_builtin_macro]
macro_rules! include { () => {} }
2021-09-24 14:17:25 -05:00
#[rustc_builtin_macro]
macro_rules! compile_error { () => {} }
2021-06-13 10:41:04 -05:00
include!("doesntexist");
//^^^^^^^ error: failed to load file `doesntexist`
2021-09-24 14:17:25 -05:00
compile_error!("compile_error macro works");
//^^^^^^^^^^^^^ error: compile_error macro works
2021-06-13 10:41:04 -05:00
"#,
);
}
#[test]
fn eager_macro_concat() {
// FIXME: this is incorrectly handling `$crate`, resulting in a wrong diagnostic.
2022-07-08 08:44:49 -05:00
// 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)
),
}
"#,
);
}
2021-06-13 10:41:04 -05:00
#[test]
fn include_macro_should_allow_empty_content() {
let mut config = DiagnosticsConfig::test_sample();
// 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,
2021-06-13 10:41:04 -05:00
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
2021-06-13 10:41:04 -05:00
"#,
);
}
#[test]
fn register_attr_and_tool() {
cov_mark::check!(register_attr);
cov_mark::check!(register_tool);
2021-06-13 11:27:14 -05:00
check_diagnostics(
2021-06-13 10:41:04 -05:00
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
2021-06-13 10:41:04 -05:00
include!("does not exist");
//^^^^^^^ error: failed to load file `does not exist`
2021-06-13 10:41:04 -05:00
env!(invalid);
//^^^ error: could not convert tokens
2021-06-13 10:41:04 -05:00
env!("OUT_DIR");
//^^^ error: `OUT_DIR` not set, enable "build scripts" to fix
2021-06-13 10:41:04 -05:00
compile_error!("compile_error works");
//^^^^^^^^^^^^^ error: compile_error works
2021-06-13 10:41:04 -05:00
// Lazy:
format_args!();
//^^^^^^^^^^^ error: no rule matches input tokens
2021-06-13 10:41:04 -05:00
}
"#,
);
}
#[test]
fn macro_rules_diag() {
check_diagnostics(
r#"
macro_rules! m {
() => {};
}
fn f() {
m!();
m!(hi);
//^ error: leftover tokens
2021-06-13 10:41:04 -05:00
}
"#,
);
}
2021-06-13 10:41:04 -05:00
#[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
"#,
)
}
#[test]
fn def_diagnostic() {
check_diagnostics(
r#"
macro_rules! foo {
//^^^ error: expected subtree
f => {};
}
fn f() {
foo!();
//^^^ error: invalid macro definition: expected subtree
}
2023-04-16 11:29:42 -05:00
"#,
)
}
#[test]
fn expansion_syntax_diagnostic() {
check_diagnostics(
r#"
macro_rules! foo {
() => { struct; };
}
fn f() {
foo!();
//^^^ error: Syntax Error in Expansion: expected a name
}
2021-06-13 10:41:04 -05:00
"#,
)
}
}