mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-22 03:44:24 +00:00
internal: refactor macro error
This commit is contained in:
parent
1e4aaee7bb
commit
00303284b5
@ -37,6 +37,7 @@ diagnostics![
|
||||
UnresolvedImport,
|
||||
UnresolvedMacroCall,
|
||||
UnresolvedProcMacro,
|
||||
MacroError,
|
||||
MissingFields,
|
||||
InactiveCode,
|
||||
];
|
||||
@ -79,35 +80,12 @@ pub struct UnresolvedProcMacro {
|
||||
pub macro_name: Option<String>,
|
||||
}
|
||||
|
||||
// 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<SyntaxNodePtr>,
|
||||
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<SyntaxNodePtr> {
|
||||
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,
|
||||
|
@ -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()),
|
||||
|
@ -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
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ mod globs;
|
||||
mod incremental;
|
||||
mod macros;
|
||||
mod mod_resolution;
|
||||
mod diagnostics;
|
||||
mod primitives;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
@ -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
|
||||
}
|
@ -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,
|
||||
|
163
crates/ide/src/diagnostics/macro_error.rs
Normal file
163
crates/ide/src/diagnostics/macro_error.rs
Normal file
@ -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
|
||||
"#,
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user