mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-07 18:58:51 +00:00
287 lines
5.9 KiB
Rust
287 lines
5.9 KiB
Rust
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, Severity};
|
|
|
|
// 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 = ctx.resolve_precise_location(&d.node, d.precise_location);
|
|
Diagnostic::new(
|
|
DiagnosticCode::Ra("macro-error", Severity::Error),
|
|
d.message.clone(),
|
|
display_range,
|
|
)
|
|
.experimental()
|
|
}
|
|
|
|
// 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.map(|it| it.syntax_node_ptr()), d.name);
|
|
Diagnostic::new(
|
|
DiagnosticCode::Ra("macro-def-error", Severity::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
|
|
|
|
compile_error! { "compile_error macro braced works" }
|
|
//^^^^^^^^^^^^^ error: compile_error macro braced works
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn eager_macro_concat() {
|
|
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!();
|
|
}
|
|
|
|
//- /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::test_sample();
|
|
|
|
// FIXME: This is a false-positive, the file is actually linked in via
|
|
// `include!` macro
|
|
config.disabled.insert("unlinked-file".to_owned());
|
|
|
|
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#"
|
|
//- minicore: fmt
|
|
#[rustc_builtin_macro]
|
|
macro_rules! env {}
|
|
|
|
#[rustc_builtin_macro]
|
|
macro_rules! include {}
|
|
|
|
#[rustc_builtin_macro]
|
|
macro_rules! compile_error {}
|
|
|
|
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: Syntax Error in Expansion: expected expression
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[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
|
|
"#,
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn def_diagnostic() {
|
|
check_diagnostics(
|
|
r#"
|
|
macro_rules! foo {
|
|
//^^^ error: expected subtree
|
|
f => {};
|
|
}
|
|
|
|
fn f() {
|
|
foo!();
|
|
//^^^ error: macro definition has parse errors
|
|
|
|
}
|
|
"#,
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn expansion_syntax_diagnostic() {
|
|
check_diagnostics(
|
|
r#"
|
|
macro_rules! foo {
|
|
() => { struct; };
|
|
}
|
|
|
|
fn f() {
|
|
foo!();
|
|
//^^^ error: Syntax Error in Expansion: expected a name
|
|
}
|
|
"#,
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn include_does_not_break_diagnostics() {
|
|
let mut config = DiagnosticsConfig::test_sample();
|
|
config.disabled.insert("inactive-code".to_owned());
|
|
config.disabled.insert("unlinked-file".to_owned());
|
|
check_diagnostics_with_config(
|
|
config,
|
|
r#"
|
|
//- minicore: include
|
|
//- /lib.rs crate:lib
|
|
include!("include-me.rs");
|
|
//- /include-me.rs
|
|
/// long doc that pushes the diagnostic range beyond the first file's text length
|
|
#[err]
|
|
//^^^^^^error: unresolved macro `err`
|
|
mod prim_never {}
|
|
"#,
|
|
);
|
|
}
|
|
}
|