fn expand_and_fill(
        &mut self,
        mut original_file: SyntaxNode,
        mut speculative_file: SyntaxNode,
        mut offset: TextSize,
        mut fake_ident_token: SyntaxToken,
    ) {
        let _p = profile::span("CompletionContext::expand_and_fill");
        let mut derive_ctx = None;

        'expansion: loop {
            let parent_item =
                |item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast);
            let ancestor_items = iter::successors(
                Option::zip(
                    find_node_at_offset::<ast::Item>(&original_file, offset),
                    find_node_at_offset::<ast::Item>(&speculative_file, offset),
                ),
                |(a, b)| parent_item(a).zip(parent_item(b)),
            );
            for (actual_item, item_with_fake_ident) in ancestor_items {
                match (
                    self.sema.expand_attr_macro(&actual_item),
                    self.sema.speculative_expand_attr_macro(
                        &actual_item,
                        &item_with_fake_ident,
                        fake_ident_token.clone(),
                    ),
                ) {
                    // maybe parent items have attributes
                    (None, None) => (),
                    // successful expansions
                    (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
                        let new_offset = fake_mapped_token.text_range().start();
                        if new_offset > actual_expansion.text_range().end() {
                            break 'expansion;
                        }
                        original_file = actual_expansion;
                        speculative_file = fake_expansion;
                        fake_ident_token = fake_mapped_token;
                        offset = new_offset;
                        continue 'expansion;
                    }
                    // exactly one expansion failed, inconsistent state so stop expanding completely
                    _ => break 'expansion,
                }
            }
            let orig_tt = match find_node_at_offset::<ast::TokenTree>(&original_file, offset) {
                Some(it) => it,
                None => break,
            };
            let spec_tt = match find_node_at_offset::<ast::TokenTree>(&speculative_file, offset) {
                Some(it) => it,
                None => break,
            };

            // Expand pseudo-derive expansion
            if let (Some(orig_attr), Some(spec_attr)) = (
                orig_tt.syntax().parent().and_then(ast::Meta::cast).and_then(|it| it.parent_attr()),
                spec_tt.syntax().parent().and_then(ast::Meta::cast).and_then(|it| it.parent_attr()),
            ) {
                match (
                    self.sema.expand_derive_as_pseudo_attr_macro(&orig_attr),
                    self.sema.speculative_expand_derive_as_pseudo_attr_macro(
                        &orig_attr,
                        &spec_attr,
                        fake_ident_token.clone(),
                    ),
                ) {
                    // Clearly not a derive macro
                    (None, None) => (),
                    // successful expansions
                    (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
                        let new_offset = fake_mapped_token.text_range().start();
                        derive_ctx = Some((actual_expansion, fake_expansion, new_offset));
                        break 'expansion;
                    }
                    // exactly one expansion failed, inconsistent state so stop expanding completely
                    _ => break 'expansion,
                }
            }

            // Expand fn-like macro calls
            if let (Some(actual_macro_call), Some(macro_call_with_fake_ident)) = (
                orig_tt.syntax().ancestors().find_map(ast::MacroCall::cast),
                spec_tt.syntax().ancestors().find_map(ast::MacroCall::cast),
            ) {
                let mac_call_path0 = actual_macro_call.path().as_ref().map(|s| s.syntax().text());
                let mac_call_path1 =
                    macro_call_with_fake_ident.path().as_ref().map(|s| s.syntax().text());
                if mac_call_path0 != mac_call_path1 {
                    break;
                }
                let speculative_args = match macro_call_with_fake_ident.token_tree() {
                    Some(tt) => tt,
                    None => break,
                };

                match (
                    self.sema.expand(&actual_macro_call),
                    self.sema.speculative_expand(
                        &actual_macro_call,
                        &speculative_args,
                        fake_ident_token.clone(),
                    ),
                ) {
                    // successful expansions
                    (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
                        let new_offset = fake_mapped_token.text_range().start();
                        if new_offset > actual_expansion.text_range().end() {
                            break;
                        }
                        original_file = actual_expansion;
                        speculative_file = fake_expansion;
                        fake_ident_token = fake_mapped_token;
                        offset = new_offset;
                        continue;
                    }
                    _ => break,
                }
            }

            break;
        }

        self.fill(&original_file, speculative_file, offset, derive_ctx);
    }
/// Do the attribute expansion at the current cursor position for both original file and fake file
/// as long as possible. As soon as one of the two expansions fail we stop to stay in sync.
Do the attribute expansion at the current cursor position for both original file and fake file
as long as possible. As soon as one of the two expansions fail we stop to stay in sync.
Do the attribute expansion at the current cursor position for both original file and fake file as long as possible . As soon as one of the two expansions fail we stop to stay in sync .
fn expand_and_fill(
        &mut self,
        mut original_file: SyntaxNode,
        mut speculative_file: SyntaxNode,
        mut offset: TextSize,
        mut fake_ident_token: SyntaxToken,
    ) {
        let _p = profile::span("CompletionContext::expand_and_fill");
        let mut derive_ctx = None;
        'expansion: loop {
            let parent_item =
                |item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast);
            let ancestor_items = iter::successors(
                Option::zip(
                    find_node_at_offset::<ast::Item>(&original_file, offset),
                    find_node_at_offset::<ast::Item>(&speculative_file, offset),
                ),
                |(a, b)| parent_item(a).zip(parent_item(b)),
            );
            for (actual_item, item_with_fake_ident) in ancestor_items {
                match (
                    self.sema.expand_attr_macro(&actual_item),
                    self.sema.speculative_expand_attr_macro(
                        &actual_item,
                        &item_with_fake_ident,
                        fake_ident_token.clone(),
                    ),
                ) {
                    // maybe parent items have attributes
                    (None, None) => (),
                    // successful expansions
                    (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
                        let new_offset = fake_mapped_token.text_range().start();
                        if new_offset > actual_expansion.text_range().end() {
                            break 'expansion;
                        }
                        original_file = actual_expansion;
                        speculative_file = fake_expansion;
                        fake_ident_token = fake_mapped_token;
                        offset = new_offset;
                        continue 'expansion;
                    }
                    // exactly one expansion failed, inconsistent state so stop expanding completely
                    _ => break 'expansion,
                }
            }
            let orig_tt = match find_node_at_offset::<ast::TokenTree>(&original_file, offset) {
                Some(it) => it,
                None => break,
            };
            let spec_tt = match find_node_at_offset::<ast::TokenTree>(&speculative_file, offset) {
                Some(it) => it,
                None => break,
            };
            // Expand pseudo-derive expansion
            if let (Some(orig_attr), Some(spec_attr)) = (
                orig_tt.syntax().parent().and_then(ast::Meta::cast).and_then(|it| it.parent_attr()),
                spec_tt.syntax().parent().and_then(ast::Meta::cast).and_then(|it| it.parent_attr()),
            ) {
                match (
                    self.sema.expand_derive_as_pseudo_attr_macro(&orig_attr),
                    self.sema.speculative_expand_derive_as_pseudo_attr_macro(
                        &orig_attr,
                        &spec_attr,
                        fake_ident_token.clone(),
                    ),
                ) {
                    // Clearly not a derive macro
                    (None, None) => (),
                    // successful expansions
                    (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
                        let new_offset = fake_mapped_token.text_range().start();
                        derive_ctx = Some((actual_expansion, fake_expansion, new_offset));
                        break 'expansion;
                    }
                    // exactly one expansion failed, inconsistent state so stop expanding completely
                    _ => break 'expansion,
                }
            }
            // Expand fn-like macro calls
            if let (Some(actual_macro_call), Some(macro_call_with_fake_ident)) = (
                orig_tt.syntax().ancestors().find_map(ast::MacroCall::cast),
                spec_tt.syntax().ancestors().find_map(ast::MacroCall::cast),
            ) {
                let mac_call_path0 = actual_macro_call.path().as_ref().map(|s| s.syntax().text());
                let mac_call_path1 =
                    macro_call_with_fake_ident.path().as_ref().map(|s| s.syntax().text());
                if mac_call_path0 != mac_call_path1 {
                    break;
                }
                let speculative_args = match macro_call_with_fake_ident.token_tree() {
                    Some(tt) => tt,
                    None => break,
                };
                match (
                    self.sema.expand(&actual_macro_call),
                    self.sema.speculative_expand(
                        &actual_macro_call,
                        &speculative_args,
                        fake_ident_token.clone(),
                    ),
                ) {
                    // successful expansions
                    (Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
                        let new_offset = fake_mapped_token.text_range().start();
                        if new_offset > actual_expansion.text_range().end() {
                            break;
                        }
                        original_file = actual_expansion;
                        speculative_file = fake_expansion;
                        fake_ident_token = fake_mapped_token;
                        offset = new_offset;
                        continue;
                    }
                    _ => break,
                }
            }
            break;
        }
        self.fill(&original_file, speculative_file, offset, derive_ctx);
    }
fn expand_and_fill ( & mut self , mut original_file : SyntaxNode , mut speculative_file : SyntaxNode , mut offset : TextSize , mut fake_ident_token : SyntaxToken , ) { let _p = profile :: span ( " " ) ; let mut derive_ctx = None ; ' expansion : loop { let parent_item = | item : & ast :: Item | item . syntax ( ) . ancestors ( ) . skip ( 1 ) . find_map ( ast :: Item :: cast ) ; let ancestor_items = iter :: successors ( Option :: zip ( find_node_at_offset :: < ast :: Item > ( & original_file , offset ) , find_node_at_offset :: < ast :: Item > ( & speculative_file , offset ) , ) , | ( a , b ) | parent_item ( a ) . zip ( parent_item ( b ) ) , ) ; for ( actual_item , item_with_fake_ident ) in ancestor_items { match ( self . sema . expand_attr_macro ( & actual_item ) , self . sema . speculative_expand_attr_macro ( & actual_item , & item_with_fake_ident , fake_ident_token . clone ( ) , ) , ) { // maybe parent items have attributes ( None , None ) => ( ) , // successful expansions ( Some ( actual_expansion ) , Some ( ( fake_expansion , fake_mapped_token ) ) ) => { let new_offset = fake_mapped_token . text_range ( ) . start ( ) ; if new_offset > actual_expansion . text_range ( ) . end ( ) { break ' expansion ; } original_file = actual_expansion ; speculative_file = fake_expansion ; fake_ident_token = fake_mapped_token ; offset = new_offset ; continue ' expansion ; } // exactly one expansion failed, inconsistent state so stop expanding completely _ => break ' expansion , } } let orig_tt = match find_node_at_offset :: < ast :: TokenTree > ( & original_file , offset ) { Some ( it ) => it , None => break , } ; let spec_tt = match find_node_at_offset :: < ast :: TokenTree > ( & speculative_file , offset ) { Some ( it ) => it , None => break , } ; // Expand pseudo-derive expansion if let ( Some ( orig_attr ) , Some ( spec_attr ) ) = ( orig_tt . syntax ( ) . parent ( ) . and_then ( ast :: Meta :: cast ) . and_then ( | it | it . parent_attr ( ) ) , spec_tt . syntax ( ) . parent ( ) . and_then ( ast :: Meta :: cast ) . and_then ( | it | it . parent_attr ( ) ) , ) { match ( self . sema . expand_derive_as_pseudo_attr_macro ( & orig_attr ) , self . sema . speculative_expand_derive_as_pseudo_attr_macro ( & orig_attr , & spec_attr , fake_ident_token . clone ( ) , ) , ) { // Clearly not a derive macro ( None , None ) => ( ) , // successful expansions ( Some ( actual_expansion ) , Some ( ( fake_expansion , fake_mapped_token ) ) ) => { let new_offset = fake_mapped_token . text_range ( ) . start ( ) ; derive_ctx = Some ( ( actual_expansion , fake_expansion , new_offset ) ) ; break ' expansion ; } // exactly one expansion failed, inconsistent state so stop expanding completely _ => break ' expansion , } } // Expand fn-like macro calls if let ( Some ( actual_macro_call ) , Some ( macro_call_with_fake_ident ) ) = ( orig_tt . syntax ( ) . ancestors ( ) . find_map ( ast :: MacroCall :: cast ) , spec_tt . syntax ( ) . ancestors ( ) . find_map ( ast :: MacroCall :: cast ) , ) { let mac_call_path0 = actual_macro_call . path ( ) . as_ref ( ) . map ( | s | s . syntax ( ) . text ( ) ) ; let mac_call_path1 = macro_call_with_fake_ident . path ( ) . as_ref ( ) . map ( | s | s . syntax ( ) . text ( ) ) ; if mac_call_path0 != mac_call_path1 { break ; } let speculative_args = match macro_call_with_fake_ident . token_tree ( ) { Some ( tt ) => tt , None => break , } ; match ( self . sema . expand ( & actual_macro_call ) , self . sema . speculative_expand ( & actual_macro_call , & speculative_args , fake_ident_token . clone ( ) , ) , ) { // successful expansions ( Some ( actual_expansion ) , Some ( ( fake_expansion , fake_mapped_token ) ) ) => { let new_offset = fake_mapped_token . text_range ( ) . start ( ) ; if new_offset > actual_expansion . text_range ( ) . end ( ) { break ; } original_file = actual_expansion ; speculative_file = fake_expansion ; fake_ident_token = fake_mapped_token ; offset = new_offset ; continue ; } _ => break , } } break ; } self . fill ( & original_file , speculative_file , offset , derive_ctx ) ; }
Do the attribute expansion at the current cursor position for both original file and fake file
as long as possible.
Do the attribute expansion at the current cursor position for both original file and fake file as long as possible .
&mut self
original_file
SyntaxNode
speculative_file
SyntaxNode
offset
TextSize
fake_ident_token
SyntaxToken
&mut self
original_file
SyntaxNode
speculative_file
SyntaxNode
offset
TextSize
fake_ident_token
SyntaxToken