Unnamed repository; edit this file 'description' to name the repository.
| -rw-r--r-- | crates/hir-expand/src/db.rs | 189 | ||||
| -rw-r--r-- | crates/hir-expand/src/lib.rs | 188 | ||||
| -rw-r--r-- | crates/hir/src/semantics.rs | 25 |
3 files changed, 191 insertions, 211 deletions
diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index b5f5785a54..5c9520d397 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -2,20 +2,12 @@ use base_db::{Crate, SourceDatabase}; use span::Span; -use syntax::{AstNode, SyntaxNode, SyntaxToken, ast}; -use syntax_bridge::{DocCommentDesugarMode, syntax_node_to_token_tree}; +use syntax::ast; use crate::{ AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerExpander, - EditionedFileId, FileRange, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, - builtin::pseudo_derive_attr_expansion, - cfg_process::attr_macro_input_to_token_tree, - declarative::DeclarativeMacroExpander, - fixup::{self, SyntaxFixupUndoInfo}, - hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt}, - proc_macro::CustomProcMacroExpander, - span_map::{RealSpanMap, SpanMap}, - tt, + EditionedFileId, FileRange, HirFileId, MacroDefId, MacroDefKind, + declarative::DeclarativeMacroExpander, proc_macro::CustomProcMacroExpander, }; #[derive(Debug, Clone, Copy, Eq, PartialEq)] @@ -62,181 +54,6 @@ fn resolve_span(db: &dyn ExpandDatabase, Span { range, anchor, ctx: _ }: Span) - FileRange { file_id, range: range + anchor_offset } } -/// This expands the given macro call, but with different arguments. This is -/// used for completion, where we want to see what 'would happen' if we insert a -/// token. The `token_to_map` mapped down into the expansion, with the mapped -/// token(s) returned with their priority. -pub fn expand_speculative( - db: &dyn ExpandDatabase, - actual_macro_call: MacroCallId, - speculative_args: &SyntaxNode, - token_to_map: SyntaxToken, -) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> { - let loc = actual_macro_call.loc(db); - let (_, _, span) = *actual_macro_call.macro_arg_considering_derives(db, &loc.kind); - - let span_map = RealSpanMap::absolute(span.anchor.file_id); - let span_map = SpanMap::RealSpanMap(&span_map); - - // Build the subtree and token mapping for the speculative args - let (mut tt, undo_info) = match &loc.kind { - MacroCallKind::FnLike { .. } => ( - syntax_bridge::syntax_node_to_token_tree( - speculative_args, - span_map, - span, - if loc.def.is_proc_macro() { - DocCommentDesugarMode::ProcMacro - } else { - DocCommentDesugarMode::Mbe - }, - ), - SyntaxFixupUndoInfo::NONE, - ), - MacroCallKind::Attr { .. } if loc.def.is_attribute_derive() => ( - syntax_bridge::syntax_node_to_token_tree( - speculative_args, - span_map, - span, - DocCommentDesugarMode::ProcMacro, - ), - SyntaxFixupUndoInfo::NONE, - ), - MacroCallKind::Derive { derive_macro_id, .. } => { - let MacroCallKind::Attr { censored_attr_ids: attr_ids, .. } = - &derive_macro_id.loc(db).kind - else { - unreachable!("`derive_macro_id` should be `MacroCallKind::Attr`"); - }; - attr_macro_input_to_token_tree( - db, - speculative_args, - span_map, - span, - true, - attr_ids, - loc.krate, - ) - } - MacroCallKind::Attr { censored_attr_ids: attr_ids, .. } => attr_macro_input_to_token_tree( - db, - speculative_args, - span_map, - span, - false, - attr_ids, - loc.krate, - ), - }; - - let attr_arg = match &loc.kind { - MacroCallKind::Attr { censored_attr_ids: attr_ids, .. } => { - if loc.def.is_attribute_derive() { - // for pseudo-derive expansion we actually pass the attribute itself only - ast::Attr::cast(speculative_args.clone()) - .and_then(|attr| { - if let ast::Meta::TokenTreeMeta(meta) = attr.meta()? { - meta.token_tree() - } else { - None - } - }) - .map(|token_tree| { - let mut tree = syntax_node_to_token_tree( - token_tree.syntax(), - span_map, - span, - DocCommentDesugarMode::ProcMacro, - ); - tree.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible); - tree.set_top_subtree_delimiter_span(tt::DelimSpan::from_single(span)); - tree - }) - } else { - // Attributes may have an input token tree, build the subtree and map for this as well - // then try finding a token id for our token if it is inside this input subtree. - let item = ast::Item::cast(speculative_args.clone())?; - let (_, meta) = - attr_ids.invoc_attr().find_attr_range_with_source_opt(db, loc.krate, &item)?; - if let ast::Meta::TokenTreeMeta(meta) = meta - && let Some(tt) = meta.token_tree() - { - let mut attr_arg = syntax_bridge::syntax_node_to_token_tree( - tt.syntax(), - span_map, - span, - DocCommentDesugarMode::ProcMacro, - ); - attr_arg.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible); - Some(attr_arg) - } else { - None - } - } - } - _ => None, - }; - - // Do the actual expansion, we need to directly expand the proc macro due to the attribute args - // Otherwise the expand query will fetch the non speculative attribute args and pass those instead. - let mut speculative_expansion = match loc.def.kind { - MacroDefKind::ProcMacro(ast, expander, _) => { - let span = crate::proc_macro_span(db, ast); - tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible); - tt.set_top_subtree_delimiter_span(tt::DelimSpan::from_single(span)); - expander.expand( - db, - loc.def.krate, - loc.krate, - &tt, - attr_arg.as_ref(), - span_with_def_site_ctxt(db, span, actual_macro_call.into(), loc.def.edition), - span_with_call_site_ctxt(db, span, actual_macro_call.into(), loc.def.edition), - span_with_mixed_site_ctxt(db, span, actual_macro_call.into(), loc.def.edition), - ) - } - MacroDefKind::BuiltInAttr(_, it) if it.is_derive() => { - pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?, span) - } - MacroDefKind::Declarative(it, _) => db - .decl_macro_expander(loc.krate, it) - .expand_unhygienic(db, &tt, loc.kind.call_style(), span), - MacroDefKind::BuiltIn(_, it) => { - it.expand(db, actual_macro_call, &tt, span).map_err(Into::into) - } - MacroDefKind::BuiltInDerive(_, it) => { - it.expand(db, actual_macro_call, &tt, span).map_err(Into::into) - } - MacroDefKind::BuiltInEager(_, it) => { - it.expand(db, actual_macro_call, &tt, span).map_err(Into::into) - } - MacroDefKind::BuiltInAttr(_, it) => it.expand(db, actual_macro_call, &tt, span), - MacroDefKind::UnimplementedBuiltIn(_) => crate::expand_unimplemented_builtin_macro(span), - }; - - let expand_to = loc.expand_to(); - - fixup::reverse_fixups(&mut speculative_expansion.value, &undo_info); - let (node, rev_tmap) = - crate::token_tree_to_syntax_node(db, &speculative_expansion.value, expand_to); - - let syntax_node = node.syntax_node(); - let token = rev_tmap - .ranges_with_span(span_map.span_for_range(token_to_map.text_range())) - .filter_map(|(range, ctx)| syntax_node.covering_element(range).into_token().zip(Some(ctx))) - .map(|(t, ctx)| { - // prefer tokens of the same kind and text, as well as non opaque marked ones - // Note the inversion of the score here, as we want to prefer the first token in case - // of all tokens having the same score - let ranking = ctx.is_opaque(db) as u8 - + 2 * (t.kind() != token_to_map.kind()) as u8 - + 4 * ((t.text() != token_to_map.text()) as u8); - (t, ranking) - }) - .collect(); - Some((node.syntax_node(), token)) -} - impl<'db> TokenExpander<'db> { fn macro_expander(db: &'db dyn ExpandDatabase, id: MacroDefId) -> TokenExpander<'db> { match id.kind { diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index c0b0a61456..75ede0c719 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -45,20 +45,20 @@ use syntax::{ Parse, SyntaxError, SyntaxNode, SyntaxToken, T, TextRange, TextSize, ast::{self, AstNode}, }; -use syntax_bridge::DocCommentDesugarMode; +use syntax_bridge::{DocCommentDesugarMode, syntax_node_to_token_tree}; use crate::{ attrs::AttrId, builtin::{ BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerExpander, - include_input_to_file_id, + include_input_to_file_id, pseudo_derive_attr_expansion, }, cfg_process::attr_macro_input_to_token_tree, db::ExpandDatabase, fixup::SyntaxFixupUndoInfo, hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt}, proc_macro::{CustomProcMacroExpander, ProcMacroKind, ProcMacros}, - span_map::{ExpansionSpanMap, SpanMap}, + span_map::{ExpansionSpanMap, RealSpanMap, SpanMap}, }; pub use crate::{ @@ -775,6 +775,184 @@ impl MacroCallId { } } +impl MacroCallId { + /// This expands the given macro call, but with different arguments. This is + /// used for completion, where we want to see what 'would happen' if we insert a + /// token. The `token_to_map` mapped down into the expansion, with the mapped + /// token(s) returned with their priority. + pub fn expand_speculative( + self, + db: &dyn ExpandDatabase, + speculative_args: &SyntaxNode, + token_to_map: SyntaxToken, + ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> { + let loc = self.loc(db); + let (_, _, span) = *self.macro_arg_considering_derives(db, &loc.kind); + + let span_map = RealSpanMap::absolute(span.anchor.file_id); + let span_map = SpanMap::RealSpanMap(&span_map); + + // Build the subtree and token mapping for the speculative args + let (mut tt, undo_info) = match &loc.kind { + MacroCallKind::FnLike { .. } => ( + syntax_bridge::syntax_node_to_token_tree( + speculative_args, + span_map, + span, + if loc.def.is_proc_macro() { + DocCommentDesugarMode::ProcMacro + } else { + DocCommentDesugarMode::Mbe + }, + ), + SyntaxFixupUndoInfo::NONE, + ), + MacroCallKind::Attr { .. } if loc.def.is_attribute_derive() => ( + syntax_bridge::syntax_node_to_token_tree( + speculative_args, + span_map, + span, + DocCommentDesugarMode::ProcMacro, + ), + SyntaxFixupUndoInfo::NONE, + ), + MacroCallKind::Derive { derive_macro_id, .. } => { + let MacroCallKind::Attr { censored_attr_ids: attr_ids, .. } = + &derive_macro_id.loc(db).kind + else { + unreachable!("`derive_macro_id` should be `MacroCallKind::Attr`"); + }; + attr_macro_input_to_token_tree( + db, + speculative_args, + span_map, + span, + true, + attr_ids, + loc.krate, + ) + } + MacroCallKind::Attr { censored_attr_ids: attr_ids, .. } => { + attr_macro_input_to_token_tree( + db, + speculative_args, + span_map, + span, + false, + attr_ids, + loc.krate, + ) + } + }; + + let attr_arg = match &loc.kind { + MacroCallKind::Attr { censored_attr_ids: attr_ids, .. } => { + if loc.def.is_attribute_derive() { + // for pseudo-derive expansion we actually pass the attribute itself only + ast::Attr::cast(speculative_args.clone()) + .and_then(|attr| { + if let ast::Meta::TokenTreeMeta(meta) = attr.meta()? { + meta.token_tree() + } else { + None + } + }) + .map(|token_tree| { + let mut tree = syntax_node_to_token_tree( + token_tree.syntax(), + span_map, + span, + DocCommentDesugarMode::ProcMacro, + ); + tree.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible); + tree.set_top_subtree_delimiter_span(tt::DelimSpan::from_single(span)); + tree + }) + } else { + // Attributes may have an input token tree, build the subtree and map for this as well + // then try finding a token id for our token if it is inside this input subtree. + let item = ast::Item::cast(speculative_args.clone())?; + let (_, meta) = attr_ids + .invoc_attr() + .find_attr_range_with_source_opt(db, loc.krate, &item)?; + if let ast::Meta::TokenTreeMeta(meta) = meta + && let Some(tt) = meta.token_tree() + { + let mut attr_arg = syntax_bridge::syntax_node_to_token_tree( + tt.syntax(), + span_map, + span, + DocCommentDesugarMode::ProcMacro, + ); + attr_arg.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible); + Some(attr_arg) + } else { + None + } + } + } + _ => None, + }; + + // Do the actual expansion, we need to directly expand the proc macro due to the attribute args + // Otherwise the expand query will fetch the non speculative attribute args and pass those instead. + let mut speculative_expansion = match loc.def.kind { + MacroDefKind::ProcMacro(ast, expander, _) => { + let span = proc_macro_span(db, ast); + tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible); + tt.set_top_subtree_delimiter_span(tt::DelimSpan::from_single(span)); + expander.expand( + db, + loc.def.krate, + loc.krate, + &tt, + attr_arg.as_ref(), + span_with_def_site_ctxt(db, span, self.into(), loc.def.edition), + span_with_call_site_ctxt(db, span, self.into(), loc.def.edition), + span_with_mixed_site_ctxt(db, span, self.into(), loc.def.edition), + ) + } + MacroDefKind::BuiltInAttr(_, it) if it.is_derive() => { + pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?, span) + } + MacroDefKind::Declarative(it, _) => db + .decl_macro_expander(loc.krate, it) + .expand_unhygienic(db, &tt, loc.kind.call_style(), span), + MacroDefKind::BuiltIn(_, it) => it.expand(db, self, &tt, span).map_err(Into::into), + MacroDefKind::BuiltInDerive(_, it) => { + it.expand(db, self, &tt, span).map_err(Into::into) + } + MacroDefKind::BuiltInEager(_, it) => it.expand(db, self, &tt, span).map_err(Into::into), + MacroDefKind::BuiltInAttr(_, it) => it.expand(db, self, &tt, span), + MacroDefKind::UnimplementedBuiltIn(_) => expand_unimplemented_builtin_macro(span), + }; + + let expand_to = loc.expand_to(); + + fixup::reverse_fixups(&mut speculative_expansion.value, &undo_info); + let (node, rev_tmap) = + token_tree_to_syntax_node(db, &speculative_expansion.value, expand_to); + + let syntax_node = node.syntax_node(); + let token = rev_tmap + .ranges_with_span(span_map.span_for_range(token_to_map.text_range())) + .filter_map(|(range, ctx)| { + syntax_node.covering_element(range).into_token().zip(Some(ctx)) + }) + .map(|(t, ctx)| { + // prefer tokens of the same kind and text, as well as non opaque marked ones + // Note the inversion of the score here, as we want to prefer the first token in case + // of all tokens having the same score + let ranking = ctx.is_opaque(db) as u8 + + 2 * (t.kind() != token_to_map.kind()) as u8 + + 4 * ((t.text() != token_to_map.text()) as u8); + (t, ranking) + }) + .collect(); + Some((node.syntax_node(), token)) + } +} + fn expand_unimplemented_builtin_macro(span: Span) -> ExpandResult<tt::TopSubtree> { ExpandResult::new( tt::TopSubtree::empty(tt::DelimSpan::from_single(span)), @@ -790,9 +968,9 @@ fn expand_unimplemented_builtin_macro(span: Span) -> ExpandResult<tt::TopSubtree fn proc_macro_span(db: &dyn ExpandDatabase, ast: AstId<ast::Fn>) -> Span { #[salsa::tracked] fn proc_macro_span(db: &dyn ExpandDatabase, ast: AstId<ast::Fn>, _: ()) -> Span { - let root = ast.file_id.parse_or_expand(db); + let (parse, span_map) = ast.file_id.parse_with_map(db); + let root = parse.syntax_node(); let ast_id_map = ast.file_id.ast_id_map(db); - let span_map = ast.file_id.span_map(db); let node = ast_id_map.get(ast.value).to_node(&root); let range = ast::HasName::name(&node) diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 02cec440e1..8023d239af 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -739,12 +739,7 @@ impl<'db> SemanticsImpl<'db> { token_to_map: SyntaxToken, ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> { let macro_file = self.to_def(actual_macro_call)?; - hir_expand::db::expand_speculative( - self.db, - macro_file, - speculative_args.syntax(), - token_to_map, - ) + self.speculative_expand_raw(macro_file, speculative_args.syntax(), token_to_map) } pub fn speculative_expand_raw( @@ -753,7 +748,7 @@ impl<'db> SemanticsImpl<'db> { speculative_args: &SyntaxNode, token_to_map: SyntaxToken, ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> { - hir_expand::db::expand_speculative(self.db, macro_file, speculative_args, token_to_map) + macro_file.expand_speculative(self.db, speculative_args, token_to_map) } /// Expand the macro call with a different item as the input, mapping the `token_to_map` down into the @@ -766,12 +761,7 @@ impl<'db> SemanticsImpl<'db> { ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> { let macro_call = self.wrap_node_infile(actual_macro_call.clone()); let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(macro_call.as_ref()))?; - hir_expand::db::expand_speculative( - self.db, - macro_call_id, - speculative_args.syntax(), - token_to_map, - ) + self.speculative_expand_raw(macro_call_id, speculative_args.syntax(), token_to_map) } pub fn speculative_expand_derive_as_pseudo_attr_macro( @@ -789,12 +779,7 @@ impl<'db> SemanticsImpl<'db> { ) .map(|(_, it, _)| it) })?; - hir_expand::db::expand_speculative( - self.db, - macro_call_id, - speculative_args.syntax(), - token_to_map, - ) + self.speculative_expand_raw(macro_call_id, speculative_args.syntax(), token_to_map) } /// Checks if renaming `renamed` to `new_name` may introduce conflicts with other locals, @@ -1980,7 +1965,7 @@ impl<'db> SemanticsImpl<'db> { } pub fn resolve_macro_call_arm(&self, macro_call: &ast::MacroCall) -> Option<u32> { - self.to_def(macro_call)?.parse_macro_expansion(self.db).value.1.matched_arm + self.to_def(macro_call)?.expansion_span_map(self.db).matched_arm } pub fn get_unsafe_ops(&self, def: ExpressionStoreOwner) -> FxHashSet<ExprOrPatSource> { |