From 56552f48399b8b1c9033adf5c389517db1dd428b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 13 May 2024 16:56:26 +0200 Subject: [PATCH] Push macro-parsing error calculation out of fundamental queries --- crates/base-db/src/lib.rs | 13 +++- crates/hir-def/src/body.rs | 13 +++- crates/hir-def/src/body/lower.rs | 4 +- crates/hir-def/src/data.rs | 70 +++++--------------- crates/hir-def/src/item_scope.rs | 8 +++ crates/hir-def/src/nameres/collector.rs | 29 +------- crates/hir-def/src/nameres/diagnostics.rs | 25 +------ crates/hir-expand/src/db.rs | 8 +-- crates/hir-expand/src/lib.rs | 6 +- crates/hir-expand/src/proc_macro.rs | 3 +- crates/hir/src/diagnostics.rs | 3 +- crates/hir/src/lib.rs | 80 +++++++++++++++++++---- crates/hir/src/source_analyzer.rs | 16 ++--- crates/ide-diagnostics/src/lib.rs | 6 +- crates/ide-diagnostics/src/tests.rs | 1 + 15 files changed, 145 insertions(+), 140 deletions(-) diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs index f8cb431c3c..2c13eed56c 100644 --- a/crates/base-db/src/lib.rs +++ b/crates/base-db/src/lib.rs @@ -8,7 +8,7 @@ mod input; use std::panic; use salsa::Durability; -use syntax::{ast, Parse, SourceFile}; +use syntax::{ast, Parse, SourceFile, SyntaxError}; use triomphe::Arc; pub use crate::{ @@ -62,6 +62,9 @@ pub trait SourceDatabase: FileLoader + std::fmt::Debug { /// Parses the file into the syntax tree. fn parse(&self, file_id: FileId) -> Parse; + /// Returns the set of errors obtained from parsing the file including validation errors. + fn parse_errors(&self, file_id: FileId) -> Option>; + /// The crate graph. #[salsa::input] fn crate_graph(&self) -> Arc; @@ -88,6 +91,14 @@ fn parse(db: &dyn SourceDatabase, file_id: FileId) -> Parse { SourceFile::parse(&text, span::Edition::CURRENT) } +fn parse_errors(db: &dyn SourceDatabase, file_id: FileId) -> Option> { + let errors = db.parse(file_id).errors(); + match &*errors { + [] => None, + [..] => Some(errors.into()), + } +} + /// We don't want to give HIR knowledge of source roots, hence we extract these /// methods into a separate DB. #[salsa::query_group(SourceDatabaseExtStorage)] diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index c9f1add275..d2f4d7b7e5 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -10,9 +10,10 @@ use std::ops::Index; use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; -use hir_expand::{name::Name, HirFileId, InFile}; +use hir_expand::{name::Name, InFile}; use la_arena::{Arena, ArenaMap}; use rustc_hash::FxHashMap; +use span::MacroFileId; use syntax::{ast, AstPtr, SyntaxNodePtr}; use triomphe::Arc; @@ -98,7 +99,7 @@ pub struct BodySourceMap { format_args_template_map: FxHashMap>, - expansions: FxHashMap>, HirFileId>, + expansions: FxHashMap>, MacroFileId>, /// Diagnostics accumulated during body lowering. These contain `AstPtr`s and so are stored in /// the source map (since they're just as volatile). @@ -349,11 +350,17 @@ impl BodySourceMap { self.expr_map.get(&src).cloned() } - pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option { + pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option { let src = node.map(AstPtr::new); self.expansions.get(&src).cloned() } + pub fn macro_calls( + &self, + ) -> impl Iterator>, MacroFileId)> + '_ { + self.expansions.iter().map(|(&a, &b)| (a, b)) + } + pub fn pat_syntax(&self, pat: PatId) -> Result { self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax) } diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index f58228c45f..82f89393ad 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -1006,7 +1006,9 @@ impl ExprCollector<'_> { Some((mark, expansion)) => { // Keep collecting even with expansion errors so we can provide completions and // other services in incomplete macro expressions. - self.source_map.expansions.insert(macro_call_ptr, self.expander.current_file_id()); + self.source_map + .expansions + .insert(macro_call_ptr, self.expander.current_file_id().macro_file().unwrap()); let prev_ast_id_map = mem::replace( &mut self.ast_id_map, self.db.ast_id_map(self.expander.current_file_id()), diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index 1b77de575c..51a4dd6f42 100644 --- a/crates/hir-def/src/data.rs +++ b/crates/hir-def/src/data.rs @@ -229,7 +229,7 @@ pub struct TraitData { /// method calls to this trait's methods when the receiver is an array and the crate edition is /// 2015 or 2018. // box it as the vec is usually empty anyways - pub attribute_calls: Option, MacroCallId)>>>, + pub macro_calls: Option, MacroCallId)>>>, } impl TraitData { @@ -258,12 +258,12 @@ impl TraitData { let mut collector = AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr)); collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items); - let (items, attribute_calls, diagnostics) = collector.finish(); + let (items, macro_calls, diagnostics) = collector.finish(); ( Arc::new(TraitData { name, - attribute_calls, + macro_calls, items, is_auto, is_unsafe, @@ -298,7 +298,7 @@ impl TraitData { } pub fn attribute_calls(&self) -> impl Iterator, MacroCallId)> + '_ { - self.attribute_calls.iter().flat_map(|it| it.iter()).copied() + self.macro_calls.iter().flat_map(|it| it.iter()).copied() } } @@ -319,7 +319,7 @@ impl TraitAliasData { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct ImplData { pub target_trait: Option>, pub self_ty: Interned, @@ -327,7 +327,7 @@ pub struct ImplData { pub is_negative: bool, pub is_unsafe: bool, // box it as the vec is usually empty anyways - pub attribute_calls: Option, MacroCallId)>>>, + pub macro_calls: Option, MacroCallId)>>>, } impl ImplData { @@ -354,7 +354,7 @@ impl ImplData { AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::ImplId(id)); collector.collect(&item_tree, tree_id.tree_id(), &impl_def.items); - let (items, attribute_calls, diagnostics) = collector.finish(); + let (items, macro_calls, diagnostics) = collector.finish(); let items = items.into_iter().map(|(_, item)| item).collect(); ( @@ -364,14 +364,14 @@ impl ImplData { items, is_negative, is_unsafe, - attribute_calls, + macro_calls, }), DefDiagnostics::new(diagnostics), ) } pub fn attribute_calls(&self) -> impl Iterator, MacroCallId)> + '_ { - self.attribute_calls.iter().flat_map(|it| it.iter()).copied() + self.macro_calls.iter().flat_map(|it| it.iter()).copied() } } @@ -573,7 +573,7 @@ struct AssocItemCollector<'a> { expander: Expander, items: Vec<(Name, AssocItemId)>, - attr_calls: Vec<(AstId, MacroCallId)>, + macro_calls: Vec<(AstId, MacroCallId)>, } impl<'a> AssocItemCollector<'a> { @@ -590,7 +590,7 @@ impl<'a> AssocItemCollector<'a> { container, expander: Expander::new(db, file_id, module_id), items: Vec::new(), - attr_calls: Vec::new(), + macro_calls: Vec::new(), diagnostics: Vec::new(), } } @@ -604,7 +604,7 @@ impl<'a> AssocItemCollector<'a> { ) { ( self.items, - if self.attr_calls.is_empty() { None } else { Some(Box::new(self.attr_calls)) }, + if self.macro_calls.is_empty() { None } else { Some(Box::new(self.macro_calls)) }, self.diagnostics, ) } @@ -662,11 +662,11 @@ impl<'a> AssocItemCollector<'a> { } } - self.attr_calls.push((ast_id, call_id)); + self.macro_calls.push((ast_id, call_id)); let res = self.expander.enter_expand_id::(self.db, call_id); - self.collect_macro_items(res, &|| loc.kind.clone()); + self.collect_macro_items(res); continue 'items; } Ok(_) => (), @@ -743,11 +743,8 @@ impl<'a> AssocItemCollector<'a> { Ok(Some(call_id)) => { let res = self.expander.enter_expand_id::(self.db, call_id); - self.collect_macro_items(res, &|| hir_expand::MacroCallKind::FnLike { - ast_id: InFile::new(file_id, ast_id), - expand_to: hir_expand::ExpandTo::Items, - eager: None, - }); + self.macro_calls.push((InFile::new(file_id, ast_id.upcast()), call_id)); + self.collect_macro_items(res); } Ok(None) => (), Err(_) => { @@ -766,39 +763,8 @@ impl<'a> AssocItemCollector<'a> { } } - fn collect_macro_items( - &mut self, - ExpandResult { value, err }: ExpandResult)>>, - error_call_kind: &dyn Fn() -> hir_expand::MacroCallKind, - ) { - let Some((mark, parse)) = value else { return }; - - if let Some(err) = err { - let diag = match err { - // why is this reported here? - hir_expand::ExpandError::UnresolvedProcMacro(krate) => { - DefDiagnostic::unresolved_proc_macro( - self.module_id.local_id, - error_call_kind(), - krate, - ) - } - _ => DefDiagnostic::macro_error( - self.module_id.local_id, - error_call_kind(), - err.to_string(), - ), - }; - self.diagnostics.push(diag); - } - let errors = parse.errors(); - if !errors.is_empty() { - self.diagnostics.push(DefDiagnostic::macro_expansion_parse_error( - self.module_id.local_id, - error_call_kind(), - errors.into_boxed_slice(), - )); - } + fn collect_macro_items(&mut self, res: ExpandResult)>>) { + let Some((mark, _parse)) = res.value else { return }; let tree_id = item_tree::TreeId::new(self.expander.current_file_id(), None); let item_tree = tree_id.item_tree(self.db); diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs index a60b9f9f3a..54cd57110e 100644 --- a/crates/hir-def/src/item_scope.rs +++ b/crates/hir-def/src/item_scope.rs @@ -234,6 +234,14 @@ impl ItemScope { self.impls.iter().copied() } + pub fn all_macro_calls(&self) -> impl Iterator + '_ { + self.macro_invocations.values().copied().chain(self.attr_macros.values().copied()).chain( + self.derive_macros.values().flat_map(|it| { + it.iter().flat_map(|it| it.derive_call_ids.iter().copied().flatten()) + }), + ) + } + pub(crate) fn modules_in_scope(&self) -> impl Iterator + '_ { self.types.values().copied().filter_map(|(def, vis, _)| match def { ModuleDefId::ModuleId(module) => Some((module, vis)), diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 30533cc45a..262bc538b9 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -15,15 +15,13 @@ use hir_expand::{ builtin_fn_macro::find_builtin_macro, name::{name, AsName, Name}, proc_macro::CustomProcMacroExpander, - ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallLoc, - MacroDefId, MacroDefKind, + ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, }; use itertools::{izip, Itertools}; use la_arena::Idx; use limit::Limit; use rustc_hash::{FxHashMap, FxHashSet}; use span::{Edition, ErasedFileAstId, FileAstId, Span, SyntaxContextId}; -use stdx::always; use syntax::ast; use triomphe::Arc; @@ -1412,31 +1410,6 @@ impl DefCollector<'_> { } let file_id = macro_call_id.as_file(); - // First, fetch the raw expansion result for purposes of error reporting. This goes through - // `parse_macro_expansion_error` to avoid depending on the full expansion result (to improve - // incrementality). - // FIXME: This kind of error fetching feels a bit odd? - let ExpandResult { value: errors, err } = - self.db.parse_macro_expansion_error(macro_call_id); - if let Some(err) = err { - let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id); - let diag = match err { - // why is this reported here? - hir_expand::ExpandError::UnresolvedProcMacro(krate) => { - always!(krate == loc.def.krate); - DefDiagnostic::unresolved_proc_macro(module_id, loc.kind.clone(), loc.def.krate) - } - _ => DefDiagnostic::macro_error(module_id, loc.kind, err.to_string()), - }; - - self.def_map.diagnostics.push(diag); - } - if !errors.is_empty() { - let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id); - let diag = DefDiagnostic::macro_expansion_parse_error(module_id, loc.kind, errors); - self.def_map.diagnostics.push(diag); - } - // Then, fetch and process the item tree. This will reuse the expansion result from above. let item_tree = self.db.file_item_tree(file_id); diff --git a/crates/hir-def/src/nameres/diagnostics.rs b/crates/hir-def/src/nameres/diagnostics.rs index 8c7fdaaf58..523a4c107b 100644 --- a/crates/hir-def/src/nameres/diagnostics.rs +++ b/crates/hir-def/src/nameres/diagnostics.rs @@ -6,7 +6,7 @@ use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; use hir_expand::{attrs::AttrId, ErasedAstId, MacroCallKind}; use la_arena::Idx; -use syntax::{ast, SyntaxError}; +use syntax::ast; use crate::{ item_tree::{self, ItemTreeId}, @@ -23,8 +23,6 @@ pub enum DefDiagnosticKind { UnconfiguredCode { ast: ErasedAstId, cfg: CfgExpr, opts: CfgOptions }, UnresolvedProcMacro { ast: MacroCallKind, krate: CrateId }, UnresolvedMacroCall { ast: MacroCallKind, path: ModPath }, - MacroError { ast: MacroCallKind, message: String }, - MacroExpansionParseError { ast: MacroCallKind, errors: Box<[SyntaxError]> }, UnimplementedBuiltinMacro { ast: AstId }, InvalidDeriveTarget { ast: AstId, id: usize }, MalformedDerive { ast: AstId, id: usize }, @@ -98,7 +96,7 @@ impl DefDiagnostic { // FIXME: This is used for a lot of things, unresolved proc macros, disabled proc macros, etc // yet the diagnostic handler in ide-diagnostics has to figure out what happened because this // struct loses all that information! - pub(crate) fn unresolved_proc_macro( + pub fn unresolved_proc_macro( container: LocalModuleId, ast: MacroCallKind, krate: CrateId, @@ -106,25 +104,6 @@ impl DefDiagnostic { Self { in_module: container, kind: DefDiagnosticKind::UnresolvedProcMacro { ast, krate } } } - pub(crate) fn macro_error( - container: LocalModuleId, - ast: MacroCallKind, - message: String, - ) -> Self { - Self { in_module: container, kind: DefDiagnosticKind::MacroError { ast, message } } - } - - pub(crate) fn macro_expansion_parse_error( - container: LocalModuleId, - ast: MacroCallKind, - errors: Box<[SyntaxError]>, - ) -> Self { - Self { - in_module: container, - kind: DefDiagnosticKind::MacroExpansionParseError { ast, errors }, - } - } - // FIXME: Whats the difference between this and unresolved_proc_macro pub(crate) fn unresolved_macro_call( container: LocalModuleId, diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index 2435a0c310..895cf20224 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -129,10 +129,11 @@ pub trait ExpandDatabase: SourceDatabase { /// user wrote in the file that defines the proc-macro. fn proc_macro_span(&self, fun: AstId) -> Span; /// Firewall query that returns the errors from the `parse_macro_expansion` query. + // FIXME: Option> fn parse_macro_expansion_error( &self, macro_call: MacroCallId, - ) -> ExpandResult>; + ) -> ExpandResult>; } /// This expands the given macro call, but with different arguments. This is @@ -357,9 +358,8 @@ fn parse_macro_expansion( fn parse_macro_expansion_error( db: &dyn ExpandDatabase, macro_call_id: MacroCallId, -) -> ExpandResult> { - db.parse_macro_expansion(MacroFileId { macro_call_id }) - .map(|it| it.0.errors().into_boxed_slice()) +) -> ExpandResult> { + db.parse_macro_expansion(MacroFileId { macro_call_id }).map(|it| it.0.errors().into()) } pub(crate) fn parse_with_map( diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index 338bd25ede..4ab989bec2 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -132,13 +132,13 @@ pub enum ExpandError { MacroDefinition, Mbe(mbe::ExpandError), RecursionOverflow, - Other(Box>), - ProcMacroPanic(Box>), + Other(Arc>), + ProcMacroPanic(Arc>), } impl ExpandError { pub fn other(msg: impl Into>) -> Self { - ExpandError::Other(Box::new(msg.into())) + ExpandError::Other(Arc::new(msg.into())) } } diff --git a/crates/hir-expand/src/proc_macro.rs b/crates/hir-expand/src/proc_macro.rs index abed16fecd..def2578b0e 100644 --- a/crates/hir-expand/src/proc_macro.rs +++ b/crates/hir-expand/src/proc_macro.rs @@ -8,6 +8,7 @@ use rustc_hash::FxHashMap; use span::Span; use stdx::never; use syntax::SmolStr; +use triomphe::Arc; use crate::{db::ExpandDatabase, tt, ExpandError, ExpandResult}; @@ -157,7 +158,7 @@ impl CustomProcMacroExpander { ProcMacroExpansionError::System(text) | ProcMacroExpansionError::Panic(text) => ExpandResult::new( tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }), - ExpandError::ProcMacroPanic(Box::new(text.into_boxed_str())), + ExpandError::ProcMacroPanic(Arc::new(text.into_boxed_str())), ), }, } diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 6e3d366c88..72272934ab 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -13,6 +13,7 @@ pub use hir_def::VariantId; use hir_def::{body::SyntheticSyntax, hir::ExprOrPatId, path::ModPath, AssocItemId, DefWithBodyId}; use hir_expand::{name::Name, HirFileId, InFile}; use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange}; +use triomphe::Arc; use crate::{AssocItem, Field, Local, MacroKind, Trait, Type}; @@ -172,7 +173,7 @@ pub struct MacroError { pub struct MacroExpansionParseError { pub node: InFile, pub precise_location: Option, - pub errors: Box<[SyntaxError]>, + pub errors: Arc<[SyntaxError]>, } #[derive(Debug, Clone, Eq, PartialEq)] diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 149e75c45c..6dd1801dae 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -59,7 +59,9 @@ use hir_def::{ ModuleId, StaticId, StructId, TraitAliasId, TraitId, TupleId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, }; -use hir_expand::{attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, MacroCallKind}; +use hir_expand::{ + attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, AstId, MacroCallKind, ValueResult, +}; use hir_ty::{ all_super_traits, autoderef, check_orphan_rules, consteval::{try_const_usize, unknown_const_as_generic, ConstExt}, @@ -79,7 +81,7 @@ use hir_ty::{ use itertools::Itertools; use nameres::diagnostics::DefDiagnosticKind; use rustc_hash::FxHashSet; -use span::Edition; +use span::{Edition, MacroCallId}; use stdx::{impl_from, never}; use syntax::{ ast::{self, HasAttrs as _, HasName}, @@ -559,6 +561,12 @@ impl Module { emit_def_diagnostic(db, acc, diag); } + if !self.id.is_block_module() { + // These are reported by the body of block modules + let scope = &def_map[self.id.local_id].scope; + scope.all_macro_calls().for_each(|it| macro_call_diagnostics(db, it, acc)); + } + for def in self.declarations(db) { match def { ModuleDef::Module(m) => { @@ -577,6 +585,10 @@ impl Module { item.diagnostics(db, acc, style_lints); } + t.all_macro_calls(db) + .iter() + .for_each(|&(_ast, call_id)| macro_call_diagnostics(db, call_id, acc)); + acc.extend(def.diagnostics(db, style_lints)) } ModuleDef::Adt(adt) => { @@ -621,6 +633,11 @@ impl Module { // FIXME: Once we diagnose the inputs to builtin derives, we should at least extract those diagnostics somehow continue; } + impl_def + .all_macro_calls(db) + .iter() + .for_each(|&(_ast, call_id)| macro_call_diagnostics(db, call_id, acc)); + let ast_id_map = db.ast_id_map(file_id); for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() { @@ -809,6 +826,35 @@ impl Module { } } +fn macro_call_diagnostics( + db: &dyn HirDatabase, + macro_call_id: MacroCallId, + acc: &mut Vec, +) { + let ValueResult { value: parse_errors, err } = db.parse_macro_expansion_error(macro_call_id); + + if let Some(err) = err { + let loc = db.lookup_intern_macro_call(macro_call_id); + let (node, precise_location, macro_name, kind) = precise_macro_call_location(&loc.kind, db); + let diag = match err { + hir_expand::ExpandError::UnresolvedProcMacro(krate) => { + UnresolvedProcMacro { node, precise_location, macro_name, kind, krate }.into() + } + err => MacroError { node, precise_location, message: err.to_string() }.into(), + }; + acc.push(diag); + } + + if !parse_errors.is_empty() { + let loc = db.lookup_intern_macro_call(macro_call_id); + let (node, precise_location, _, _) = precise_macro_call_location(&loc.kind, db); + acc.push( + MacroExpansionParseError { node, precise_location, errors: parse_errors.clone() } + .into(), + ) + } +} + fn emit_macro_def_diagnostics(db: &dyn HirDatabase, acc: &mut Vec, m: Macro) { let id = db.macro_def(m.id); if let hir_expand::db::TokenExpander::DeclarativeMacro(expander) = db.macro_expander(id) { @@ -888,16 +934,6 @@ fn emit_def_diagnostic_( .into(), ); } - DefDiagnosticKind::MacroError { ast, message } => { - let (node, precise_location, _, _) = precise_macro_call_location(ast, db); - acc.push(MacroError { node, precise_location, message: message.clone() }.into()); - } - DefDiagnosticKind::MacroExpansionParseError { ast, errors } => { - let (node, precise_location, _, _) = precise_macro_call_location(ast, db); - acc.push( - MacroExpansionParseError { node, precise_location, errors: errors.clone() }.into(), - ); - } DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => { let node = ast.to_node(db.upcast()); // Must have a name, otherwise we wouldn't emit it. @@ -1644,6 +1680,10 @@ impl DefWithBody { Module { id: def_map.module_id(DefMap::ROOT) }.diagnostics(db, acc, style_lints); } + source_map + .macro_calls() + .for_each(|(_ast_id, call_id)| macro_call_diagnostics(db, call_id.macro_call_id, acc)); + for diag in source_map.diagnostics() { acc.push(match diag { BodyDiagnostic::InactiveCode { node, cfg, opts } => { @@ -2445,6 +2485,14 @@ impl Trait { .filter(|(_, ty)| !count_required_only || !ty.has_default()) .count() } + + fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId, MacroCallId)]> { + db.trait_data(self.id) + .macro_calls + .as_ref() + .map(|it| it.as_ref().clone().into_boxed_slice()) + .unwrap_or_default() + } } impl HasVisibility for Trait { @@ -3751,6 +3799,14 @@ impl Impl { pub fn check_orphan_rules(self, db: &dyn HirDatabase) -> bool { check_orphan_rules(db, self.id) } + + fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId, MacroCallId)]> { + db.impl_data(self.id) + .macro_calls + .as_ref() + .map(|it| it.as_ref().clone().into_boxed_slice()) + .unwrap_or_default() + } } #[derive(Clone, PartialEq, Eq, Debug, Hash)] diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index dc96a1b03d..057b03baef 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -28,7 +28,7 @@ use hir_expand::{ mod_path::path, name, name::{AsName, Name}, - HirFileId, InFile, MacroFileId, MacroFileIdExt, + HirFileId, InFile, InMacroFile, MacroFileId, MacroFileIdExt, }; use hir_ty::{ diagnostics::{ @@ -118,7 +118,7 @@ impl SourceAnalyzer { fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option { let src = match expr { ast::Expr::MacroExpr(expr) => { - self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?))? + self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?))?.into() } _ => InFile::new(self.file_id, expr.clone()), }; @@ -145,20 +145,20 @@ impl SourceAnalyzer { &self, db: &dyn HirDatabase, expr: InFile, - ) -> Option> { + ) -> Option> { let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?; - let expanded = db.parse_or_expand(macro_file); + let expanded = db.parse_macro_expansion(macro_file).value.0.syntax_node(); let res = if let Some(stmts) = ast::MacroStmts::cast(expanded.clone()) { match stmts.expr()? { ast::Expr::MacroExpr(mac) => { - self.expand_expr(db, InFile::new(macro_file, mac.macro_call()?))? + self.expand_expr(db, InFile::new(macro_file.into(), mac.macro_call()?))? } - expr => InFile::new(macro_file, expr), + expr => InMacroFile::new(macro_file, expr), } } else if let Some(call) = ast::MacroCall::cast(expanded.clone()) { - self.expand_expr(db, InFile::new(macro_file, call))? + self.expand_expr(db, InFile::new(macro_file.into(), call))? } else { - InFile::new(macro_file, ast::Expr::cast(expanded)?) + InMacroFile::new(macro_file, ast::Expr::cast(expanded)?) }; Some(res) diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index c3ced36a69..54fde5d839 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -297,11 +297,10 @@ pub fn diagnostics( ) -> Vec { let _p = tracing::span!(tracing::Level::INFO, "diagnostics").entered(); let sema = Semantics::new(db); - let parse = db.parse(file_id); let mut res = Vec::new(); // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily. - res.extend(parse.errors().into_iter().take(128).map(|err| { + res.extend(db.parse_errors(file_id).as_deref().into_iter().flatten().take(128).map(|err| { Diagnostic::new( DiagnosticCode::RustcHardError("syntax-error"), format!("Syntax Error: {err}"), @@ -340,7 +339,8 @@ pub fn diagnostics( AnyDiagnostic::MacroDefError(d) => handlers::macro_error::macro_def_error(&ctx, &d), AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d), AnyDiagnostic::MacroExpansionParseError(d) => { - res.extend(d.errors.iter().take(32).map(|err| { + // FIXME: Point to the correct error span here, not just the macro-call name + res.extend(d.errors.iter().take(16).map(|err| { { Diagnostic::new( DiagnosticCode::RustcHardError("syntax-error"), diff --git a/crates/ide-diagnostics/src/tests.rs b/crates/ide-diagnostics/src/tests.rs index cd5e95cc1e..8bf062fd61 100644 --- a/crates/ide-diagnostics/src/tests.rs +++ b/crates/ide-diagnostics/src/tests.rs @@ -246,6 +246,7 @@ pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixtur } } if expected != actual { + dbg!(&actual); let fneg = expected .iter() .filter(|x| !actual.contains(x))