1
1
//! See `CompletionContext` structure.
2
2
3
+ use std:: iter;
4
+
3
5
use base_db:: SourceDatabaseExt ;
4
6
use hir:: { Local , Name , ScopeDef , Semantics , SemanticsScope , Type , TypeInfo } ;
5
7
use ide_db:: {
@@ -431,12 +433,17 @@ impl<'a> CompletionContext<'a> {
431
433
mut fake_ident_token : SyntaxToken ,
432
434
) {
433
435
let _p = profile:: span ( "CompletionContext::expand_and_fill" ) ;
434
- loop {
435
- // Expand attributes
436
- if let ( Some ( actual_item) , Some ( item_with_fake_ident) ) = (
437
- find_node_at_offset :: < ast:: Item > ( & original_file, offset) ,
438
- find_node_at_offset :: < ast:: Item > ( & speculative_file, offset) ,
439
- ) {
436
+ ' expansion: loop {
437
+ let parent_item =
438
+ |item : & ast:: Item | item. syntax ( ) . ancestors ( ) . skip ( 1 ) . find_map ( ast:: Item :: cast) ;
439
+ let ancestor_items = iter:: successors (
440
+ Option :: zip (
441
+ find_node_at_offset :: < ast:: Item > ( & original_file, offset) ,
442
+ find_node_at_offset :: < ast:: Item > ( & speculative_file, offset) ,
443
+ ) ,
444
+ |( a, b) | parent_item ( a) . zip ( parent_item ( b) ) ,
445
+ ) ;
446
+ for ( actual_item, item_with_fake_ident) in ancestor_items {
440
447
match (
441
448
self . sema . expand_attr_macro ( & actual_item) ,
442
449
self . sema . speculative_expand_attr_macro (
@@ -445,19 +452,22 @@ impl<'a> CompletionContext<'a> {
445
452
fake_ident_token. clone ( ) ,
446
453
) ,
447
454
) {
448
- ( Some ( actual_expansion) , Some ( speculative_expansion) ) => {
449
- let new_offset = speculative_expansion. 1 . text_range ( ) . start ( ) ;
455
+ // maybe parent items have attributes
456
+ ( None , None ) => ( ) ,
457
+ // successful expansions
458
+ ( Some ( actual_expansion) , Some ( ( fake_expansion, fake_mapped_token) ) ) => {
459
+ let new_offset = fake_mapped_token. text_range ( ) . start ( ) ;
450
460
if new_offset > actual_expansion. text_range ( ) . end ( ) {
451
- break ;
461
+ break ' expansion ;
452
462
}
453
463
original_file = actual_expansion;
454
- speculative_file = speculative_expansion . 0 ;
455
- fake_ident_token = speculative_expansion . 1 ;
464
+ speculative_file = fake_expansion ;
465
+ fake_ident_token = fake_mapped_token ;
456
466
offset = new_offset;
457
- continue ;
467
+ continue ' expansion ;
458
468
}
459
- ( None , None ) => ( ) ,
460
- _ => break ,
469
+ // exactly one expansion failed, inconsistent state so stop expanding completely
470
+ _ => break ' expansion ,
461
471
}
462
472
}
463
473
@@ -477,28 +487,31 @@ impl<'a> CompletionContext<'a> {
477
487
None => break ,
478
488
} ;
479
489
480
- if let ( Some ( actual_expansion ) , Some ( speculative_expansion ) ) = (
490
+ match (
481
491
self . sema . expand ( & actual_macro_call) ,
482
492
self . sema . speculative_expand (
483
493
& actual_macro_call,
484
494
& speculative_args,
485
- fake_ident_token,
495
+ fake_ident_token. clone ( ) ,
486
496
) ,
487
497
) {
488
- let new_offset = speculative_expansion. 1 . text_range ( ) . start ( ) ;
489
- if new_offset > actual_expansion. text_range ( ) . end ( ) {
490
- break ;
498
+ // successful expansions
499
+ ( Some ( actual_expansion) , Some ( ( fake_expansion, fake_mapped_token) ) ) => {
500
+ let new_offset = fake_mapped_token. text_range ( ) . start ( ) ;
501
+ if new_offset > actual_expansion. text_range ( ) . end ( ) {
502
+ break ;
503
+ }
504
+ original_file = actual_expansion;
505
+ speculative_file = fake_expansion;
506
+ fake_ident_token = fake_mapped_token;
507
+ offset = new_offset;
508
+ continue ;
491
509
}
492
- original_file = actual_expansion;
493
- speculative_file = speculative_expansion. 0 ;
494
- fake_ident_token = speculative_expansion. 1 ;
495
- offset = new_offset;
496
- } else {
497
- break ;
510
+ _ => break ,
498
511
}
499
- } else {
500
- break ;
501
512
}
513
+
514
+ break ;
502
515
}
503
516
504
517
self . fill ( & original_file, speculative_file, offset) ;
0 commit comments