diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 3f62a2cd334c3..193ef904de95f 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -628,35 +628,42 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec, diag: } DefDiagnosticKind::UnresolvedProcMacro { ast } => { - let mut precise_location = None; - let (node, macro_name) = match ast { + let (node, precise_location, macro_name) = match ast { MacroCallKind::FnLike { ast_id, .. } => { 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 } => { let node = ast_id.to_node(db.upcast()); - // Compute the precise location of the macro name's token in the derive // list. let token = (|| { - let derive_attr = node.attrs().nth(*derive_attr_index as usize)?; - derive_attr + let derive_attr = node + .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() .children_with_tokens() .filter_map(|elem| match elem { syntax::NodeOrToken::Token(tok) => Some(tok), _ => None, }) - .group_by(|t| t.kind() == T![,]) + .group_by(|t| t.kind() == T![,]); + let (_, mut group) = group_by .into_iter() .filter(|&(comma, _)| !comma) - .nth(*derive_index as usize) - .and_then(|(_, mut g)| g.find(|t| t.kind() == T![ident])) + .nth(*derive_index as usize)?; + 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))), + token.as_ref().map(|tok| tok.text_range()), token.as_ref().map(ToString::to_string), ) } @@ -667,8 +674,10 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec, diag: .nth((*invoc_attr_index) as usize) .and_then(Either::left) .unwrap_or_else(|| panic!("cannot find attribute #{}", invoc_attr_index)); + ( ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))), + Some(attr.syntax().text_range()), attr.path() .and_then(|path| path.segment()) .and_then(|seg| seg.name_ref()) diff --git a/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs b/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs index fde1d1323f5bc..fea3a0e8323d0 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs @@ -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 // `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( ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedProcMacro, + attr_proc_macros_enabled: bool, ) -> 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); - // FIXME: it would be nice to tell the user whether proc macros are currently disabled let message = match &d.macro_name { Some(name) => format!("proc macro `{}` not expanded", name), 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 }) } diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index 1d4ea461d0845..1cbe8ad72bb16 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -139,6 +139,7 @@ impl Default for ExprFillDefaultMode { #[derive(Default, Debug, Clone)] pub struct DiagnosticsConfig { + pub attr_proc_macros_enabled: bool, pub disable_experimental: bool, pub disabled: FxHashSet, pub expr_fill_default: ExprFillDefaultMode, @@ -204,7 +205,7 @@ pub fn diagnostics( AnyDiagnostic::UnresolvedImport(d) => handlers::unresolved_import::unresolved_import(&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::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::InactiveCode(d) => match handlers::inactive_code::inactive_code(&ctx, &d) { diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 9fd19589999e6..fcc4cbebc5e57 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -856,6 +856,7 @@ impl Config { pub fn diagnostics(&self) -> DiagnosticsConfig { DiagnosticsConfig { + attr_proc_macros_enabled: self.expand_proc_attr_macros(), disable_experimental: !self.data.diagnostics_experimental_enable, disabled: self.data.diagnostics_disabled.clone(), expr_fill_default: match self.data.assist_expressionFillDefault { @@ -893,7 +894,7 @@ impl Config { } 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 {