Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir_expand/src/db.rs')
| -rw-r--r-- | crates/hir_expand/src/db.rs | 67 |
1 files changed, 42 insertions, 25 deletions
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 14fe5cd3bb..80ba7a8d14 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs @@ -141,27 +141,40 @@ pub trait AstDatabase: SourceDatabase { pub fn expand_speculative( db: &dyn AstDatabase, actual_macro_call: MacroCallId, - speculative_args: &ast::TokenTree, + speculative_args: &SyntaxNode, token_to_map: SyntaxToken, ) -> Option<(SyntaxNode, SyntaxToken)> { - let (tt, tmap_1) = mbe::syntax_node_to_token_tree(speculative_args.syntax()); - let range = - token_to_map.text_range().checked_sub(speculative_args.syntax().text_range().start())?; - let token_id = tmap_1.token_by_range(range)?; - - let macro_def = { - let loc: MacroCallLoc = db.lookup_intern_macro(actual_macro_call); - db.macro_def(loc.def)? - }; + let loc = db.lookup_intern_macro(actual_macro_call); + let macro_def = db.macro_def(loc.def)?; + + // Fetch token id in the speculative args + let censor = censor_for_macro_input(&loc, &speculative_args); + let (tt, args_tmap) = mbe::syntax_node_to_token_tree_censored(&speculative_args, censor); + let range = token_to_map.text_range().checked_sub(speculative_args.text_range().start())?; + let token_id = args_tmap.token_by_range(range)?; + + let speculative_expansion = if let MacroDefKind::ProcMacro(expander, ..) = loc.def.kind { + let attr_arg = match &loc.kind { + // FIXME make attr arg speculative as well + MacroCallKind::Attr { attr_args, .. } => { + let mut attr_args = attr_args.0.clone(); + mbe::Shift::new(&tt).shift_all(&mut attr_args); + Some(attr_args) + } + _ => None, + }; - let speculative_expansion = macro_def.expand(db, actual_macro_call, &tt); + expander.expand(db, loc.krate, &tt, attr_arg.as_ref()) + } else { + macro_def.expand(db, actual_macro_call, &tt) + }; let expand_to = macro_expand_to(db, actual_macro_call); - - let (node, tmap_2) = token_tree_to_syntax_node(&speculative_expansion.value, expand_to).ok()?; + let (node, rev_tmap) = + token_tree_to_syntax_node(&speculative_expansion.value, expand_to).ok()?; let token_id = macro_def.map_id_down(token_id); - let range = tmap_2.first_range_by_token(token_id, token_to_map.kind())?; + let range = rev_tmap.first_range_by_token(token_id, token_to_map.kind())?; let token = node.syntax_node().covering_element(range).into_token()?; Some((node.syntax_node(), token)) } @@ -259,7 +272,19 @@ fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, let loc = db.lookup_intern_macro(id); let node = SyntaxNode::new_root(arg); - let censor = match loc.kind { + let censor = censor_for_macro_input(&loc, &node); + let (mut tt, tmap) = mbe::syntax_node_to_token_tree_censored(&node, censor); + + if loc.def.is_proc_macro() { + // proc macros expect their inputs without parentheses, MBEs expect it with them included + tt.delimiter = None; + } + + Some(Arc::new((tt, tmap))) +} + +fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> Option<TextRange> { + match loc.kind { MacroCallKind::FnLike { .. } => None, MacroCallKind::Derive { derive_attr_index, .. } => match ast::Item::cast(node.clone()) { Some(item) => item @@ -275,15 +300,7 @@ fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, } None => None, }, - }; - let (mut tt, tmap) = mbe::syntax_node_to_token_tree_censored(&node, censor); - - if loc.def.is_proc_macro() { - // proc macros expect their inputs without parentheses, MBEs expect it with them included - tt.delimiter = None; } - - Some(Arc::new((tt, tmap))) } fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> { @@ -367,11 +384,11 @@ fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<Option<Ar None => return ExpandResult::str_err("Failed to lower macro args to token tree".into()), }; - let macro_rules = match db.macro_def(loc.def) { + let expander = match db.macro_def(loc.def) { Some(it) => it, None => return ExpandResult::str_err("Failed to find macro definition".into()), }; - let ExpandResult { value: tt, err } = macro_rules.expand(db, id, ¯o_arg.0); + let ExpandResult { value: tt, err } = expander.expand(db, id, ¯o_arg.0); // Set a hard limit for the expanded tt let count = tt.count(); // XXX: Make ExpandResult a real error and use .map_err instead? |