/// 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 returned.
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 returned.
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 returned .
pub fn expand_speculative(
    db: &dyn AstDatabase,
    actual_macro_call: MacroCallId,
    speculative_args: &SyntaxNode,
    token_to_map: SyntaxToken,
) -> Option<(SyntaxNode, SyntaxToken)> {
    let loc = db.lookup_intern_macro_call(actual_macro_call);
    let macro_def = db.macro_def(loc.def).ok()?;
    let token_range = token_to_map.text_range();
    // Build the subtree and token mapping for the speculative args
    let censor = censor_for_macro_input(&loc, &speculative_args);
    let mut fixups = fixup::fixup_syntax(&speculative_args);
    fixups.replace.extend(censor.into_iter().map(|node| (node, Vec::new())));
    let (mut tt, spec_args_tmap, _) = mbe::syntax_node_to_token_tree_with_modifications(
        &speculative_args,
        fixups.token_map,
        fixups.next_id,
        fixups.replace,
        fixups.append,
    );
    let (attr_arg, token_id) = match loc.kind {
        MacroCallKind::Attr { invoc_attr_index, is_derive, .. } => {
            let attr = if is_derive {
                // for pseudo-derive expansion we actually pass the attribute itself only
                ast::Attr::cast(speculative_args.clone())
            } 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())?;
                item.doc_comments_and_attrs().nth(invoc_attr_index as usize).and_then(Either::left)
            }?;
            match attr.token_tree() {
                Some(token_tree) => {
                    let (mut tree, map) = syntax_node_to_token_tree(attr.token_tree()?.syntax());
                    tree.delimiter = None;
                    let shift = mbe::Shift::new(&tt);
                    shift.shift_all(&mut tree);
                    let token_id = if token_tree.syntax().text_range().contains_range(token_range) {
                        let attr_input_start =
                            token_tree.left_delimiter_token()?.text_range().start();
                        let range = token_range.checked_sub(attr_input_start)?;
                        let token_id = shift.shift(map.token_by_range(range)?);
                        Some(token_id)
                    } else {
                        None
                    };
                    (Some(tree), token_id)
                }
                _ => (None, None),
            }
        }
        _ => (None, None),
    };
    let token_id = match token_id {
        Some(token_id) => token_id,
        // token wasn't inside an attribute input so it has to be in the general macro input
        None => {
            let range = token_range.checked_sub(speculative_args.text_range().start())?;
            let token_id = spec_args_tmap.token_by_range(range)?;
            macro_def.map_id_down(token_id)
        }
    };
    // 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(expander, ..) => {
            tt.delimiter = None;
            expander.expand(db, loc.krate, &tt, attr_arg.as_ref())
        }
        MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => {
            pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?)
        }
        _ => macro_def.expand(db, actual_macro_call, &tt),
    };
    let expand_to = macro_expand_to(db, actual_macro_call);
    fixup::reverse_fixups(&mut speculative_expansion.value, &spec_args_tmap, &fixups.undo_info);
    let (node, rev_tmap) = token_tree_to_syntax_node(&speculative_expansion.value, expand_to);
    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))
}
pub fn expand_speculative ( db : & dyn AstDatabase , actual_macro_call : MacroCallId , speculative_args : & SyntaxNode , token_to_map : SyntaxToken , ) -> Option < ( SyntaxNode , SyntaxToken ) > { let loc = db . lookup_intern_macro_call ( actual_macro_call ) ; let macro_def = db . macro_def ( loc . def ) . ok ( ) ? ; let token_range = token_to_map . text_range ( ) ; // Build the subtree and token mapping for the speculative args let censor = censor_for_macro_input ( & loc , & speculative_args ) ; let mut fixups = fixup :: fixup_syntax ( & speculative_args ) ; fixups . replace . extend ( censor . into_iter ( ) . map ( | node | ( node , Vec :: new ( ) ) ) ) ; let ( mut tt , spec_args_tmap , _ ) = mbe :: syntax_node_to_token_tree_with_modifications ( & speculative_args , fixups . token_map , fixups . next_id , fixups . replace , fixups . append , ) ; let ( attr_arg , token_id ) = match loc . kind { MacroCallKind :: Attr { invoc_attr_index , is_derive , .. } => { let attr = if is_derive { // for pseudo-derive expansion we actually pass the attribute itself only ast :: Attr :: cast ( speculative_args . clone ( ) ) } 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 ( ) ) ? ; item . doc_comments_and_attrs ( ) . nth ( invoc_attr_index as usize ) . and_then ( Either :: left ) } ? ; match attr . token_tree ( ) { Some ( token_tree ) => { let ( mut tree , map ) = syntax_node_to_token_tree ( attr . token_tree ( ) ? . syntax ( ) ) ; tree . delimiter = None ; let shift = mbe :: Shift :: new ( & tt ) ; shift . shift_all ( & mut tree ) ; let token_id = if token_tree . syntax ( ) . text_range ( ) . contains_range ( token_range ) { let attr_input_start = token_tree . left_delimiter_token ( ) ? . text_range ( ) . start ( ) ; let range = token_range . checked_sub ( attr_input_start ) ? ; let token_id = shift . shift ( map . token_by_range ( range ) ? ) ; Some ( token_id ) } else { None } ; ( Some ( tree ) , token_id ) } _ => ( None , None ) , } } _ => ( None , None ) , } ; let token_id = match token_id { Some ( token_id ) => token_id , // token wasn't inside an attribute input so it has to be in the general macro input None => { let range = token_range . checked_sub ( speculative_args . text_range ( ) . start ( ) ) ? ; let token_id = spec_args_tmap . token_by_range ( range ) ? ; macro_def . map_id_down ( token_id ) } } ; // 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 ( expander , .. ) => { tt . delimiter = None ; expander . expand ( db , loc . krate , & tt , attr_arg . as_ref ( ) ) } MacroDefKind :: BuiltInAttr ( BuiltinAttrExpander :: Derive , _ ) => { pseudo_derive_attr_expansion ( & tt , attr_arg . as_ref ( ) ? ) } _ => macro_def . expand ( db , actual_macro_call , & tt ) , } ; let expand_to = macro_expand_to ( db , actual_macro_call ) ; fixup :: reverse_fixups ( & mut speculative_expansion . value , & spec_args_tmap , & fixups . undo_info ) ; let ( node , rev_tmap ) = token_tree_to_syntax_node ( & speculative_expansion . value , expand_to ) ; 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 ) ) }
This expands the given macro call, but with different arguments.
This expands the given macro call but with different arguments .
db
&dyn AstDatabase
actual_macro_call
MacroCallId
speculative_args
&SyntaxNode
token_to_map
SyntaxToken