11use hir:: Semantics ;
22use ide_db:: {
3- base_db:: { FileId , FilePosition } ,
3+ base_db:: { FileId , FilePosition , FileRange } ,
44 defs:: { Definition , IdentClass } ,
55 helpers:: pick_best_token,
66 search:: { FileReference , ReferenceCategory , SearchScope } ,
@@ -30,6 +30,7 @@ pub struct HighlightRelatedConfig {
3030 pub references : bool ,
3131 pub exit_points : bool ,
3232 pub break_points : bool ,
33+ pub closure_captures : bool ,
3334 pub yield_points : bool ,
3435}
3536
@@ -53,11 +54,12 @@ pub(crate) fn highlight_related(
5354
5455 let token = pick_best_token ( syntax. token_at_offset ( offset) , |kind| match kind {
5556 T ! [ ?] => 4 , // prefer `?` when the cursor is sandwiched like in `await$0?`
56- T ! [ ->] => 3 ,
57+ T ! [ ->] | T ! [ | ] => 3 ,
5758 kind if kind. is_keyword ( ) => 2 ,
5859 IDENT | INT_NUMBER => 1 ,
5960 _ => 0 ,
6061 } ) ?;
62+ // most if not all of these should be re-implemented with information seeded from hir
6163 match token. kind ( ) {
6264 T ! [ ?] if config. exit_points && token. parent ( ) . and_then ( ast:: TryExpr :: cast) . is_some ( ) => {
6365 highlight_exit_points ( sema, token)
@@ -70,11 +72,64 @@ pub(crate) fn highlight_related(
7072 T ! [ break ] | T ! [ loop ] | T ! [ while ] | T ! [ continue ] if config. break_points => {
7173 highlight_break_points ( token)
7274 }
75+ T ! [ |] if config. closure_captures => highlight_closure_captures (
76+ sema,
77+ token. parent_ancestors ( ) . nth ( 1 ) . and_then ( ast:: ClosureExpr :: cast) ?,
78+ file_id,
79+ ) ,
80+ T ! [ move] if config. closure_captures => highlight_closure_captures (
81+ sema,
82+ token. parent ( ) . and_then ( ast:: ClosureExpr :: cast) ?,
83+ file_id,
84+ ) ,
7385 _ if config. references => highlight_references ( sema, & syntax, token, file_id) ,
7486 _ => None ,
7587 }
7688}
7789
90+ fn highlight_closure_captures (
91+ sema : & Semantics < ' _ , RootDatabase > ,
92+ node : ast:: ClosureExpr ,
93+ file_id : FileId ,
94+ ) -> Option < Vec < HighlightedRange > > {
95+ let search_range = node. body ( ) ?. syntax ( ) . text_range ( ) ;
96+ let ty = & sema. type_of_expr ( & node. into ( ) ) ?. original ;
97+ let c = ty. as_closure ( ) ?;
98+ Some (
99+ c. captured_items ( sema. db )
100+ . into_iter ( )
101+ . map ( |capture| capture. local ( ) )
102+ . flat_map ( |local| {
103+ let usages = Definition :: Local ( local)
104+ . usages ( sema)
105+ . set_scope ( Some ( SearchScope :: file_range ( FileRange {
106+ file_id,
107+ range : search_range,
108+ } ) ) )
109+ . include_self_refs ( )
110+ . all ( )
111+ . references
112+ . remove ( & file_id)
113+ . into_iter ( )
114+ . flatten ( )
115+ . map ( |FileReference { category, range, .. } | HighlightedRange {
116+ range,
117+ category,
118+ } ) ;
119+ let category = local. is_mut ( sema. db ) . then_some ( ReferenceCategory :: Write ) ;
120+ local
121+ . sources ( sema. db )
122+ . into_iter ( )
123+ . map ( |x| x. to_nav ( sema. db ) )
124+ . filter ( |decl| decl. file_id == file_id)
125+ . filter_map ( |decl| decl. focus_range )
126+ . map ( move |range| HighlightedRange { range, category } )
127+ . chain ( usages)
128+ } )
129+ . collect ( ) ,
130+ )
131+ }
132+
78133fn highlight_references (
79134 sema : & Semantics < ' _ , RootDatabase > ,
80135 node : & SyntaxNode ,
@@ -93,10 +148,7 @@ fn highlight_references(
93148 . remove ( & file_id)
94149 } )
95150 . flatten ( )
96- . map ( |FileReference { category : access, range, .. } | HighlightedRange {
97- range,
98- category : access,
99- } ) ;
151+ . map ( |FileReference { category, range, .. } | HighlightedRange { range, category } ) ;
100152 let mut res = FxHashSet :: default ( ) ;
101153 for & def in & defs {
102154 match def {
@@ -352,16 +404,17 @@ mod tests {
352404
353405 use super :: * ;
354406
407+ const ENABLED_CONFIG : HighlightRelatedConfig = HighlightRelatedConfig {
408+ break_points : true ,
409+ exit_points : true ,
410+ references : true ,
411+ closure_captures : true ,
412+ yield_points : true ,
413+ } ;
414+
355415 #[ track_caller]
356416 fn check ( ra_fixture : & str ) {
357- let config = HighlightRelatedConfig {
358- break_points : true ,
359- exit_points : true ,
360- references : true ,
361- yield_points : true ,
362- } ;
363-
364- check_with_config ( ra_fixture, config) ;
417+ check_with_config ( ra_fixture, ENABLED_CONFIG ) ;
365418 }
366419
367420 #[ track_caller]
@@ -1086,12 +1139,7 @@ fn function(field: u32) {
10861139
10871140 #[ test]
10881141 fn test_hl_disabled_ref_local ( ) {
1089- let config = HighlightRelatedConfig {
1090- references : false ,
1091- break_points : true ,
1092- exit_points : true ,
1093- yield_points : true ,
1094- } ;
1142+ let config = HighlightRelatedConfig { references : false , ..ENABLED_CONFIG } ;
10951143
10961144 check_with_config (
10971145 r#"
@@ -1106,12 +1154,7 @@ fn foo() {
11061154
11071155 #[ test]
11081156 fn test_hl_disabled_ref_local_preserved_break ( ) {
1109- let config = HighlightRelatedConfig {
1110- references : false ,
1111- break_points : true ,
1112- exit_points : true ,
1113- yield_points : true ,
1114- } ;
1157+ let config = HighlightRelatedConfig { references : false , ..ENABLED_CONFIG } ;
11151158
11161159 check_with_config (
11171160 r#"
@@ -1146,12 +1189,7 @@ fn foo() {
11461189
11471190 #[ test]
11481191 fn test_hl_disabled_ref_local_preserved_yield ( ) {
1149- let config = HighlightRelatedConfig {
1150- references : false ,
1151- break_points : true ,
1152- exit_points : true ,
1153- yield_points : true ,
1154- } ;
1192+ let config = HighlightRelatedConfig { references : false , ..ENABLED_CONFIG } ;
11551193
11561194 check_with_config (
11571195 r#"
@@ -1182,12 +1220,7 @@ async fn foo() {
11821220
11831221 #[ test]
11841222 fn test_hl_disabled_ref_local_preserved_exit ( ) {
1185- let config = HighlightRelatedConfig {
1186- references : false ,
1187- break_points : true ,
1188- exit_points : true ,
1189- yield_points : true ,
1190- } ;
1223+ let config = HighlightRelatedConfig { references : false , ..ENABLED_CONFIG } ;
11911224
11921225 check_with_config (
11931226 r#"
@@ -1225,12 +1258,7 @@ fn foo() ->$0 i32 {
12251258
12261259 #[ test]
12271260 fn test_hl_disabled_break ( ) {
1228- let config = HighlightRelatedConfig {
1229- references : true ,
1230- break_points : false ,
1231- exit_points : true ,
1232- yield_points : true ,
1233- } ;
1261+ let config = HighlightRelatedConfig { break_points : false , ..ENABLED_CONFIG } ;
12341262
12351263 check_with_config (
12361264 r#"
@@ -1246,12 +1274,7 @@ fn foo() {
12461274
12471275 #[ test]
12481276 fn test_hl_disabled_yield ( ) {
1249- let config = HighlightRelatedConfig {
1250- references : true ,
1251- break_points : true ,
1252- exit_points : true ,
1253- yield_points : false ,
1254- } ;
1277+ let config = HighlightRelatedConfig { yield_points : false , ..ENABLED_CONFIG } ;
12551278
12561279 check_with_config (
12571280 r#"
@@ -1265,12 +1288,7 @@ async$0 fn foo() {
12651288
12661289 #[ test]
12671290 fn test_hl_disabled_exit ( ) {
1268- let config = HighlightRelatedConfig {
1269- references : true ,
1270- break_points : true ,
1271- exit_points : false ,
1272- yield_points : true ,
1273- } ;
1291+ let config = HighlightRelatedConfig { exit_points : false , ..ENABLED_CONFIG } ;
12741292
12751293 check_with_config (
12761294 r#"
@@ -1411,6 +1429,34 @@ impl Trait for () {
14111429 type Output$0 = ();
14121430 // ^^^^^^
14131431}
1432+ "# ,
1433+ ) ;
1434+ }
1435+
1436+ #[ test]
1437+ fn test_closure_capture_pipe ( ) {
1438+ check (
1439+ r#"
1440+ fn f() {
1441+ let x = 1;
1442+ // ^
1443+ let c = $0|y| x + y;
1444+ // ^ read
1445+ }
1446+ "# ,
1447+ ) ;
1448+ }
1449+
1450+ #[ test]
1451+ fn test_closure_capture_move ( ) {
1452+ check (
1453+ r#"
1454+ fn f() {
1455+ let x = 1;
1456+ // ^
1457+ let c = move$0 |y| x + y;
1458+ // ^ read
1459+ }
14141460"# ,
14151461 ) ;
14161462 }
0 commit comments