More precise proc-macro errors

This commit is contained in:
Lukas Wirth 2022-06-12 18:44:46 +02:00
parent 4f2a67b26f
commit 0e4eb647f6
4 changed files with 31 additions and 15 deletions

View file

@ -628,35 +628,42 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag:
} }
DefDiagnosticKind::UnresolvedProcMacro { ast } => { DefDiagnosticKind::UnresolvedProcMacro { ast } => {
let mut precise_location = None; let (node, precise_location, macro_name) = match ast {
let (node, macro_name) = match ast {
MacroCallKind::FnLike { ast_id, .. } => { MacroCallKind::FnLike { ast_id, .. } => {
let node = ast_id.to_node(db.upcast()); let node = ast_id.to_node(db.upcast());
(ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))), None) (
ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
node.path().map(|it| it.syntax().text_range()),
node.path().and_then(|it| it.segment()).map(|it| it.to_string()),
)
} }
MacroCallKind::Derive { ast_id, derive_attr_index, derive_index } => { MacroCallKind::Derive { ast_id, derive_attr_index, derive_index } => {
let node = ast_id.to_node(db.upcast()); let node = ast_id.to_node(db.upcast());
// Compute the precise location of the macro name's token in the derive // Compute the precise location of the macro name's token in the derive
// list. // list.
let token = (|| { let token = (|| {
let derive_attr = node.attrs().nth(*derive_attr_index as usize)?; let derive_attr = node
derive_attr .doc_comments_and_attrs()
.nth(*derive_attr_index as usize)
.and_then(Either::left)?;
let token_tree = derive_attr.meta()?.token_tree()?;
let group_by = token_tree
.syntax() .syntax()
.children_with_tokens() .children_with_tokens()
.filter_map(|elem| match elem { .filter_map(|elem| match elem {
syntax::NodeOrToken::Token(tok) => Some(tok), syntax::NodeOrToken::Token(tok) => Some(tok),
_ => None, _ => None,
}) })
.group_by(|t| t.kind() == T![,]) .group_by(|t| t.kind() == T![,]);
let (_, mut group) = group_by
.into_iter() .into_iter()
.filter(|&(comma, _)| !comma) .filter(|&(comma, _)| !comma)
.nth(*derive_index as usize) .nth(*derive_index as usize)?;
.and_then(|(_, mut g)| g.find(|t| t.kind() == T![ident])) group.find(|t| t.kind() == T![ident])
})(); })();
precise_location = token.as_ref().map(|tok| tok.text_range());
( (
ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))), ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
token.as_ref().map(|tok| tok.text_range()),
token.as_ref().map(ToString::to_string), token.as_ref().map(ToString::to_string),
) )
} }
@ -667,8 +674,10 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag:
.nth((*invoc_attr_index) as usize) .nth((*invoc_attr_index) as usize)
.and_then(Either::left) .and_then(Either::left)
.unwrap_or_else(|| panic!("cannot find attribute #{}", invoc_attr_index)); .unwrap_or_else(|| panic!("cannot find attribute #{}", invoc_attr_index));
( (
ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))), ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))),
Some(attr.syntax().text_range()),
attr.path() attr.path()
.and_then(|path| path.segment()) .and_then(|path| path.segment())
.and_then(|seg| seg.name_ref()) .and_then(|seg| seg.name_ref())

View file

@ -8,20 +8,25 @@ use crate::{Diagnostic, DiagnosticsContext, Severity};
// //
// If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the // If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the
// `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can // `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can
// enable support for procedural macros (see `rust-analyzer.procMacro.enable`). // enable support for procedural macros (see `rust-analyzer.procMacro.attributes.enable`).
pub(crate) fn unresolved_proc_macro( pub(crate) fn unresolved_proc_macro(
ctx: &DiagnosticsContext<'_>, ctx: &DiagnosticsContext<'_>,
d: &hir::UnresolvedProcMacro, d: &hir::UnresolvedProcMacro,
attr_proc_macros_enabled: bool,
) -> Diagnostic { ) -> Diagnostic {
// Use more accurate position if available. // Use more accurate position if available.
let display_range = d let display_range = d
.precise_location .precise_location
.unwrap_or_else(|| ctx.sema.diagnostics_display_range(d.node.clone()).range); .unwrap_or_else(|| ctx.sema.diagnostics_display_range(d.node.clone()).range);
// FIXME: it would be nice to tell the user whether proc macros are currently disabled
let message = match &d.macro_name { let message = match &d.macro_name {
Some(name) => format!("proc macro `{}` not expanded", name), Some(name) => format!("proc macro `{}` not expanded", name),
None => "proc macro not expanded".to_string(), None => "proc macro not expanded".to_string(),
}; };
let message = format!(
"{message}{}",
if attr_proc_macros_enabled { "" } else { " (attribute macro expansion is disabled)" }
);
Diagnostic::new("unresolved-proc-macro", message, display_range).severity(Severity::WeakWarning) Diagnostic::new("unresolved-proc-macro", message, display_range)
.severity(if attr_proc_macros_enabled { Severity::Error } else { Severity::WeakWarning })
} }

View file

@ -139,6 +139,7 @@ impl Default for ExprFillDefaultMode {
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
pub struct DiagnosticsConfig { pub struct DiagnosticsConfig {
pub attr_proc_macros_enabled: bool,
pub disable_experimental: bool, pub disable_experimental: bool,
pub disabled: FxHashSet<String>, pub disabled: FxHashSet<String>,
pub expr_fill_default: ExprFillDefaultMode, pub expr_fill_default: ExprFillDefaultMode,
@ -204,7 +205,7 @@ pub fn diagnostics(
AnyDiagnostic::UnresolvedImport(d) => handlers::unresolved_import::unresolved_import(&ctx, &d), AnyDiagnostic::UnresolvedImport(d) => handlers::unresolved_import::unresolved_import(&ctx, &d),
AnyDiagnostic::UnresolvedMacroCall(d) => handlers::unresolved_macro_call::unresolved_macro_call(&ctx, &d), AnyDiagnostic::UnresolvedMacroCall(d) => handlers::unresolved_macro_call::unresolved_macro_call(&ctx, &d),
AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d), AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d),
AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d), AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d, config.attr_proc_macros_enabled),
AnyDiagnostic::InvalidDeriveTarget(d) => handlers::invalid_derive_target::invalid_derive_target(&ctx, &d), AnyDiagnostic::InvalidDeriveTarget(d) => handlers::invalid_derive_target::invalid_derive_target(&ctx, &d),
AnyDiagnostic::InactiveCode(d) => match handlers::inactive_code::inactive_code(&ctx, &d) { AnyDiagnostic::InactiveCode(d) => match handlers::inactive_code::inactive_code(&ctx, &d) {

View file

@ -856,6 +856,7 @@ impl Config {
pub fn diagnostics(&self) -> DiagnosticsConfig { pub fn diagnostics(&self) -> DiagnosticsConfig {
DiagnosticsConfig { DiagnosticsConfig {
attr_proc_macros_enabled: self.expand_proc_attr_macros(),
disable_experimental: !self.data.diagnostics_experimental_enable, disable_experimental: !self.data.diagnostics_experimental_enable,
disabled: self.data.diagnostics_disabled.clone(), disabled: self.data.diagnostics_disabled.clone(),
expr_fill_default: match self.data.assist_expressionFillDefault { expr_fill_default: match self.data.assist_expressionFillDefault {
@ -893,7 +894,7 @@ impl Config {
} }
pub fn expand_proc_attr_macros(&self) -> bool { pub fn expand_proc_attr_macros(&self) -> bool {
self.data.procMacro_attributes_enable self.data.procMacro_enable && self.data.procMacro_attributes_enable
} }
pub fn files(&self) -> FilesConfig { pub fn files(&self) -> FilesConfig {