@@ -456,7 +456,7 @@ impl<'a> CompletionContext<'a> {
456
456
ast:: IdentPat ( bind_pat) => {
457
457
let mut pat_ctx = pattern_context_for( sema, original_file, bind_pat. into( ) ) ;
458
458
if let Some ( record_field) = ast:: RecordPatField :: for_field_name( & name) {
459
- pat_ctx. record_pat = find_node_in_file_compensated( original_file, & record_field. parent_record_pat( ) ) ;
459
+ pat_ctx. record_pat = find_node_in_file_compensated( sema , original_file, & record_field. parent_record_pat( ) ) ;
460
460
}
461
461
462
462
NameKind :: IdentPat ( pat_ctx)
@@ -493,9 +493,13 @@ impl<'a> CompletionContext<'a> {
493
493
|kind| ( NameRefContext { nameref : nameref. clone ( ) , kind } , Default :: default ( ) ) ;
494
494
495
495
if let Some ( record_field) = ast:: RecordExprField :: for_field_name ( & name_ref) {
496
- return find_node_in_file_compensated ( original_file, & record_field. parent_record_lit ( ) )
497
- . map ( NameRefKind :: RecordExpr )
498
- . map ( make_res) ;
496
+ return find_node_in_file_compensated (
497
+ sema,
498
+ original_file,
499
+ & record_field. parent_record_lit ( ) ,
500
+ )
501
+ . map ( NameRefKind :: RecordExpr )
502
+ . map ( make_res) ;
499
503
}
500
504
if let Some ( record_field) = ast:: RecordPatField :: for_field_name_ref ( & name_ref) {
501
505
let kind = NameRefKind :: Pattern ( PatternContext {
@@ -504,6 +508,7 @@ impl<'a> CompletionContext<'a> {
504
508
ref_token : None ,
505
509
mut_token : None ,
506
510
record_pat : find_node_in_file_compensated (
511
+ sema,
507
512
original_file,
508
513
& record_field. parent_record_pat ( ) ,
509
514
) ,
@@ -568,7 +573,7 @@ impl<'a> CompletionContext<'a> {
568
573
} ;
569
574
let func_update_record = |syn : & SyntaxNode | {
570
575
if let Some ( record_expr) = syn. ancestors ( ) . nth ( 2 ) . and_then ( ast:: RecordExpr :: cast) {
571
- find_node_in_file_compensated ( original_file, & record_expr)
576
+ find_node_in_file_compensated ( sema , original_file, & record_expr)
572
577
} else {
573
578
None
574
579
}
@@ -670,9 +675,9 @@ impl<'a> CompletionContext<'a> {
670
675
ast:: TypeBound ( _) => TypeLocation :: TypeBound ,
671
676
// is this case needed?
672
677
ast:: TypeBoundList ( _) => TypeLocation :: TypeBound ,
673
- ast:: GenericArg ( it) => TypeLocation :: GenericArgList ( find_opt_node_in_file_compensated( original_file, it. syntax( ) . parent( ) . and_then( ast:: GenericArgList :: cast) ) ) ,
678
+ ast:: GenericArg ( it) => TypeLocation :: GenericArgList ( find_opt_node_in_file_compensated( sema , original_file, it. syntax( ) . parent( ) . and_then( ast:: GenericArgList :: cast) ) ) ,
674
679
// is this case needed?
675
- ast:: GenericArgList ( it) => TypeLocation :: GenericArgList ( find_opt_node_in_file_compensated( original_file, Some ( it) ) ) ,
680
+ ast:: GenericArgList ( it) => TypeLocation :: GenericArgList ( find_opt_node_in_file_compensated( sema , original_file, Some ( it) ) ) ,
676
681
ast:: TupleField ( _) => TypeLocation :: TupleField ,
677
682
_ => return None ,
678
683
}
@@ -734,7 +739,7 @@ impl<'a> CompletionContext<'a> {
734
739
_ => Some ( None ) ,
735
740
} ;
736
741
737
- match dbg ! ( find_node_in_file_compensated( original_file, & expr) ) {
742
+ match find_node_in_file_compensated ( sema , original_file, & expr) {
738
743
Some ( it) => {
739
744
let innermost_ret_ty = sema
740
745
. ancestors_with_macros ( it. syntax ( ) . clone ( ) )
@@ -757,7 +762,7 @@ impl<'a> CompletionContext<'a> {
757
762
. parent ( )
758
763
. and_then ( ast:: LetStmt :: cast)
759
764
. map_or ( false , |it| it. semicolon_token ( ) . is_none ( ) ) ;
760
- let impl_ = fetch_immediate_impl ( sema, original_file, & expr) ;
765
+ let impl_ = fetch_immediate_impl ( sema, original_file, expr. syntax ( ) ) ;
761
766
762
767
PathKind :: Expr {
763
768
in_block_expr,
@@ -826,7 +831,7 @@ impl<'a> CompletionContext<'a> {
826
831
match it {
827
832
ast:: Trait ( _) => ItemListKind :: Trait ,
828
833
ast:: Impl ( it) => if it. trait_( ) . is_some( ) {
829
- ItemListKind :: TraitImpl ( find_node_in_file_compensated( original_file, & it) )
834
+ ItemListKind :: TraitImpl ( find_node_in_file_compensated( sema , original_file, & it) )
830
835
} else {
831
836
ItemListKind :: Impl
832
837
} ,
@@ -983,7 +988,7 @@ fn pattern_context_for(
983
988
let has_type_ascription = param. ty( ) . is_some( ) ;
984
989
is_param = ( || {
985
990
let fake_param_list = param. syntax( ) . parent( ) . and_then( ast:: ParamList :: cast) ?;
986
- let param_list = find_node_in_file_compensated( original_file, & fake_param_list) ?;
991
+ let param_list = find_node_in_file_compensated( sema , original_file, & fake_param_list) ?;
987
992
let param_list_owner = param_list. syntax( ) . parent( ) ?;
988
993
let kind = match_ast! {
989
994
match param_list_owner {
@@ -1017,42 +1022,25 @@ fn pattern_context_for(
1017
1022
mut_token,
1018
1023
ref_token,
1019
1024
record_pat : None ,
1020
- impl_ : fetch_immediate_impl ( sema, original_file, & pat) ,
1025
+ impl_ : fetch_immediate_impl ( sema, original_file, pat. syntax ( ) ) ,
1021
1026
}
1022
1027
}
1023
1028
1024
1029
fn fetch_immediate_impl (
1025
1030
sema : & Semantics < RootDatabase > ,
1026
1031
original_file : & SyntaxNode ,
1027
- node : & impl AstNode ,
1032
+ node : & SyntaxNode ,
1028
1033
) -> Option < ast:: Impl > {
1029
- // FIXME: The fallback here could be done better
1030
- let ( f, s) = match find_node_in_file_compensated ( original_file, node) {
1031
- Some ( node) => {
1032
- let mut items = sema
1033
- . ancestors_with_macros ( node. syntax ( ) . clone ( ) )
1034
- . filter_map ( ast:: Item :: cast)
1035
- . filter ( |it| !matches ! ( it, ast:: Item :: MacroCall ( _) ) )
1036
- . take ( 2 ) ;
1037
- ( items. next ( ) , items. next ( ) )
1038
- }
1039
- None => {
1040
- let mut items = node
1041
- . syntax ( )
1042
- . ancestors ( )
1043
- . filter_map ( ast:: Item :: cast)
1044
- . filter ( |it| !matches ! ( it, ast:: Item :: MacroCall ( _) ) )
1045
- . take ( 2 ) ;
1046
- ( items. next ( ) , items. next ( ) )
1047
- }
1048
- } ;
1034
+ let mut ancestors = ancestors_in_file_compensated ( sema, original_file, node) ?
1035
+ . filter_map ( ast:: Item :: cast)
1036
+ . filter ( |it| !matches ! ( it, ast:: Item :: MacroCall ( _) ) ) ;
1049
1037
1050
- match f ? {
1038
+ match ancestors . next ( ) ? {
1051
1039
ast:: Item :: Const ( _) | ast:: Item :: Fn ( _) | ast:: Item :: TypeAlias ( _) => ( ) ,
1052
1040
ast:: Item :: Impl ( it) => return Some ( it) ,
1053
1041
_ => return None ,
1054
1042
}
1055
- match s ? {
1043
+ match ancestors . next ( ) ? {
1056
1044
ast:: Item :: Impl ( it) => Some ( it) ,
1057
1045
_ => None ,
1058
1046
}
@@ -1076,27 +1064,44 @@ fn find_node_in_file<N: AstNode>(syntax: &SyntaxNode, node: &N) -> Option<N> {
1076
1064
/// Attempts to find `node` inside `syntax` via `node`'s text range while compensating
1077
1065
/// for the offset introduced by the fake ident.
1078
1066
/// This is wrong if `node` comes before the insertion point! Use `find_node_in_file` instead.
1079
- fn find_node_in_file_compensated < N : AstNode > ( syntax : & SyntaxNode , node : & N ) -> Option < N > {
1080
- let syntax_range = syntax. text_range ( ) ;
1081
- let range = node. syntax ( ) . text_range ( ) ;
1067
+ fn find_node_in_file_compensated < N : AstNode > (
1068
+ sema : & Semantics < RootDatabase > ,
1069
+ in_file : & SyntaxNode ,
1070
+ node : & N ,
1071
+ ) -> Option < N > {
1072
+ ancestors_in_file_compensated ( sema, in_file, node. syntax ( ) ) ?. find_map ( N :: cast)
1073
+ }
1074
+
1075
+ fn ancestors_in_file_compensated < ' sema > (
1076
+ sema : & ' sema Semantics < RootDatabase > ,
1077
+ in_file : & SyntaxNode ,
1078
+ node : & SyntaxNode ,
1079
+ ) -> Option < impl Iterator < Item = SyntaxNode > + ' sema > {
1080
+ let syntax_range = in_file. text_range ( ) ;
1081
+ let range = node. text_range ( ) ;
1082
1082
let end = range. end ( ) . checked_sub ( TextSize :: try_from ( COMPLETION_MARKER . len ( ) ) . ok ( ) ?) ?;
1083
1083
if end < range. start ( ) {
1084
1084
return None ;
1085
1085
}
1086
1086
let range = TextRange :: new ( range. start ( ) , end) ;
1087
1087
// our inserted ident could cause `range` to go outside of the original syntax, so cap it
1088
1088
let intersection = range. intersect ( syntax_range) ?;
1089
- syntax. covering_element ( intersection) . ancestors ( ) . find_map ( N :: cast)
1089
+ let node = match in_file. covering_element ( intersection) {
1090
+ NodeOrToken :: Node ( node) => node,
1091
+ NodeOrToken :: Token ( tok) => tok. parent ( ) ?,
1092
+ } ;
1093
+ Some ( sema. ancestors_with_macros ( node) )
1090
1094
}
1091
1095
1092
1096
/// Attempts to find `node` inside `syntax` via `node`'s text range while compensating
1093
1097
/// for the offset introduced by the fake ident..
1094
1098
/// This is wrong if `node` comes before the insertion point! Use `find_node_in_file` instead.
1095
1099
fn find_opt_node_in_file_compensated < N : AstNode > (
1100
+ sema : & Semantics < RootDatabase > ,
1096
1101
syntax : & SyntaxNode ,
1097
1102
node : Option < N > ,
1098
1103
) -> Option < N > {
1099
- find_node_in_file_compensated ( syntax, & node?)
1104
+ find_node_in_file_compensated ( sema , syntax, & node?)
1100
1105
}
1101
1106
1102
1107
fn path_or_use_tree_qualifier ( path : & ast:: Path ) -> Option < ( ast:: Path , bool ) > {
0 commit comments