@@ -9,21 +9,22 @@ use ra_syntax::{
99 SyntaxNode , SyntaxToken , TextRange , TextUnit , TokenAtOffset , T ,
1010} ;
1111
12- use crate :: { db:: RootDatabase , FileRange } ;
13- use hir:: { db:: AstDatabase , InFile } ;
12+ use crate :: { db:: RootDatabase , expand :: descend_into_macros , FileId , FileRange } ;
13+ use hir:: db:: AstDatabase ;
1414use itertools:: Itertools ;
1515
1616pub ( crate ) fn extend_selection ( db : & RootDatabase , frange : FileRange ) -> TextRange {
1717 let src = db. parse ( frange. file_id ) . tree ( ) ;
18- let root = InFile :: new ( frange. file_id . into ( ) , src. syntax ( ) ) ;
19- try_extend_selection ( db, root, frange. range ) . unwrap_or ( frange. range )
18+ try_extend_selection ( db, src. syntax ( ) , frange) . unwrap_or ( frange. range )
2019}
2120
2221fn try_extend_selection (
2322 db : & RootDatabase ,
24- root : InFile < & SyntaxNode > ,
25- range : TextRange ,
23+ root : & SyntaxNode ,
24+ frange : FileRange ,
2625) -> Option < TextRange > {
26+ let range = frange. range ;
27+
2728 let string_kinds = [ COMMENT , STRING , RAW_STRING , BYTE_STRING , RAW_BYTE_STRING ] ;
2829 let list_kinds = [
2930 RECORD_FIELD_PAT_LIST ,
@@ -46,9 +47,9 @@ fn try_extend_selection(
4647
4748 if range. is_empty ( ) {
4849 let offset = range. start ( ) ;
49- let mut leaves = root. value . token_at_offset ( offset) ;
50+ let mut leaves = root. token_at_offset ( offset) ;
5051 if leaves. clone ( ) . all ( |it| it. kind ( ) == WHITESPACE ) {
51- return Some ( extend_ws ( root. value , leaves. next ( ) ?, offset) ) ;
52+ return Some ( extend_ws ( root, leaves. next ( ) ?, offset) ) ;
5253 }
5354 let leaf_range = match leaves {
5455 TokenAtOffset :: None => return None ,
@@ -64,7 +65,7 @@ fn try_extend_selection(
6465 } ;
6566 return Some ( leaf_range) ;
6667 } ;
67- let node = match find_covering_element ( root. value , range) {
68+ let node = match find_covering_element ( root, range) {
6869 NodeOrToken :: Token ( token) => {
6970 if token. text_range ( ) != range {
7071 return Some ( token. text_range ( ) ) ;
@@ -82,7 +83,7 @@ fn try_extend_selection(
8283 // if we are in single token_tree, we maybe live in macro or attr
8384 if node. kind ( ) == TOKEN_TREE {
8485 if let Some ( macro_call) = node. ancestors ( ) . find_map ( ast:: MacroCall :: cast) {
85- if let Some ( range) = extend_tokens_from_range ( db, & root , macro_call, range) {
86+ if let Some ( range) = extend_tokens_from_range ( db, frange . file_id , macro_call, range) {
8687 return Some ( range) ;
8788 }
8889 }
@@ -105,48 +106,52 @@ fn try_extend_selection(
105106
106107fn extend_tokens_from_range (
107108 db : & RootDatabase ,
108- root : & InFile < & SyntaxNode > ,
109+ file_id : FileId ,
109110 macro_call : ast:: MacroCall ,
110111 original_range : TextRange ,
111112) -> Option < TextRange > {
112- let analyzer = hir:: SourceAnalyzer :: new ( db, root. clone ( ) , None ) ;
113- let expansion = analyzer. expand ( db, root. with_value ( & macro_call) ) ?;
114-
115113 // compute original mapped token range
114+ let mut expanded = None ;
116115 let range = macro_call
117116 . syntax ( )
118117 . descendants_with_tokens ( )
119118 . filter_map ( |n| match n {
120119 NodeOrToken :: Token ( token) if token. text_range ( ) . is_subrange ( & original_range) => {
121- expansion
122- . map_token_down ( db, root. with_value ( & token) )
123- . map ( |node| node. value . text_range ( ) )
120+ let node = descend_into_macros ( db, file_id, token) ;
121+ match node. file_id {
122+ it if it == file_id. into ( ) => None ,
123+ it if expanded. is_none ( ) || expanded == Some ( it) => {
124+ expanded = Some ( it. into ( ) ) ;
125+ Some ( node. value . text_range ( ) )
126+ }
127+ _ => None ,
128+ }
124129 }
125130 _ => None ,
126131 } )
127132 . fold1 ( |x, y| union_range ( x, y) ) ?;
128133
129- let src = db. parse_or_expand ( expansion. file_id ( ) ) ?;
134+ let expanded = expanded?;
135+ let src = db. parse_or_expand ( expanded) ?;
130136 let parent = shallowest_node ( & find_covering_element ( & src, range) ) ?. parent ( ) ?;
131-
132137 // compute parent mapped token range
133138 let range = macro_call
134139 . syntax ( )
135140 . descendants_with_tokens ( )
136141 . filter_map ( |n| match n {
137142 NodeOrToken :: Token ( token) => {
138- expansion. map_token_down ( db, root. with_value ( & token) ) . and_then ( |node| {
139- if node. value . text_range ( ) . is_subrange ( & parent. text_range ( ) ) {
140- Some ( token. text_range ( ) )
141- } else {
142- None
143- }
144- } )
143+ let node = descend_into_macros ( db, file_id, token. clone ( ) ) ;
144+ if node. file_id == expanded
145+ && node. value . text_range ( ) . is_subrange ( & parent. text_range ( ) )
146+ {
147+ Some ( token. text_range ( ) )
148+ } else {
149+ None
150+ }
145151 }
146152 _ => None ,
147153 } )
148154 . fold1 ( |x, y| union_range ( x, y) ) ?;
149-
150155 if original_range. is_subrange ( & range) && original_range != range {
151156 Some ( range)
152157 } else {
@@ -597,4 +602,21 @@ fn main() { let var = (
597602 ] ,
598603 ) ;
599604 }
605+
606+ #[ test]
607+ fn extend_selection_inside_recur_macros ( ) {
608+ do_check (
609+ r#" macro_rules! foo2 { ($item:item) => {$item} }
610+ macro_rules! foo { ($item:item) => {foo2!($item);} }
611+ foo!{fn hello(na<|>me:usize){}}"# ,
612+ & [
613+ "name" ,
614+ "name:usize" ,
615+ "(name:usize)" ,
616+ "fn hello(name:usize){}" ,
617+ "{fn hello(name:usize){}}" ,
618+ "foo!{fn hello(name:usize){}}" ,
619+ ] ,
620+ ) ;
621+ }
600622}
0 commit comments