1
1
use hir:: Semantics ;
2
2
use ide_db:: {
3
- base_db:: { FileId , FilePosition } ,
3
+ base_db:: { FileId , FilePosition , FileRange } ,
4
4
defs:: { Definition , IdentClass } ,
5
5
helpers:: pick_best_token,
6
6
search:: { FileReference , ReferenceCategory , SearchScope } ,
@@ -30,6 +30,7 @@ pub struct HighlightRelatedConfig {
30
30
pub references : bool ,
31
31
pub exit_points : bool ,
32
32
pub break_points : bool ,
33
+ pub closure_captures : bool ,
33
34
pub yield_points : bool ,
34
35
}
35
36
@@ -53,11 +54,12 @@ pub(crate) fn highlight_related(
53
54
54
55
let token = pick_best_token ( syntax. token_at_offset ( offset) , |kind| match kind {
55
56
T ! [ ?] => 4 , // prefer `?` when the cursor is sandwiched like in `await$0?`
56
- T ! [ ->] => 3 ,
57
+ T ! [ ->] | T ! [ | ] => 3 ,
57
58
kind if kind. is_keyword ( ) => 2 ,
58
59
IDENT | INT_NUMBER => 1 ,
59
60
_ => 0 ,
60
61
} ) ?;
62
+ // most if not all of these should be re-implemented with information seeded from hir
61
63
match token. kind ( ) {
62
64
T ! [ ?] if config. exit_points && token. parent ( ) . and_then ( ast:: TryExpr :: cast) . is_some ( ) => {
63
65
highlight_exit_points ( sema, token)
@@ -70,11 +72,64 @@ pub(crate) fn highlight_related(
70
72
T ! [ break ] | T ! [ loop ] | T ! [ while ] | T ! [ continue ] if config. break_points => {
71
73
highlight_break_points ( token)
72
74
}
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
+ ) ,
73
85
_ if config. references => highlight_references ( sema, & syntax, token, file_id) ,
74
86
_ => None ,
75
87
}
76
88
}
77
89
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
+
78
133
fn highlight_references (
79
134
sema : & Semantics < ' _ , RootDatabase > ,
80
135
node : & SyntaxNode ,
@@ -93,10 +148,7 @@ fn highlight_references(
93
148
. remove ( & file_id)
94
149
} )
95
150
. flatten ( )
96
- . map ( |FileReference { category : access, range, .. } | HighlightedRange {
97
- range,
98
- category : access,
99
- } ) ;
151
+ . map ( |FileReference { category, range, .. } | HighlightedRange { range, category } ) ;
100
152
let mut res = FxHashSet :: default ( ) ;
101
153
for & def in & defs {
102
154
match def {
@@ -352,16 +404,17 @@ mod tests {
352
404
353
405
use super :: * ;
354
406
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
+
355
415
#[ track_caller]
356
416
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 ) ;
365
418
}
366
419
367
420
#[ track_caller]
@@ -1086,12 +1139,7 @@ fn function(field: u32) {
1086
1139
1087
1140
#[ test]
1088
1141
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 } ;
1095
1143
1096
1144
check_with_config (
1097
1145
r#"
@@ -1106,12 +1154,7 @@ fn foo() {
1106
1154
1107
1155
#[ test]
1108
1156
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 } ;
1115
1158
1116
1159
check_with_config (
1117
1160
r#"
@@ -1146,12 +1189,7 @@ fn foo() {
1146
1189
1147
1190
#[ test]
1148
1191
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 } ;
1155
1193
1156
1194
check_with_config (
1157
1195
r#"
@@ -1182,12 +1220,7 @@ async fn foo() {
1182
1220
1183
1221
#[ test]
1184
1222
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 } ;
1191
1224
1192
1225
check_with_config (
1193
1226
r#"
@@ -1225,12 +1258,7 @@ fn foo() ->$0 i32 {
1225
1258
1226
1259
#[ test]
1227
1260
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 } ;
1234
1262
1235
1263
check_with_config (
1236
1264
r#"
@@ -1246,12 +1274,7 @@ fn foo() {
1246
1274
1247
1275
#[ test]
1248
1276
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 } ;
1255
1278
1256
1279
check_with_config (
1257
1280
r#"
@@ -1265,12 +1288,7 @@ async$0 fn foo() {
1265
1288
1266
1289
#[ test]
1267
1290
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 } ;
1274
1292
1275
1293
check_with_config (
1276
1294
r#"
@@ -1411,6 +1429,34 @@ impl Trait for () {
1411
1429
type Output$0 = ();
1412
1430
// ^^^^^^
1413
1431
}
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
+ }
1414
1460
"# ,
1415
1461
) ;
1416
1462
}
0 commit comments