@@ -2,15 +2,17 @@ use hir::Semantics;
2
2
use ide_db:: {
3
3
base_db:: { FileId , FilePosition } ,
4
4
defs:: { Definition , IdentClass } ,
5
- helpers:: { for_each_break_expr, for_each_tail_expr, node_ext:: walk_expr, pick_best_token} ,
5
+ helpers:: {
6
+ for_each_break_and_continue_expr, for_each_tail_expr, node_ext:: walk_expr, pick_best_token,
7
+ } ,
6
8
search:: { FileReference , ReferenceCategory , SearchScope } ,
7
9
RootDatabase ,
8
10
} ;
9
11
use rustc_hash:: FxHashSet ;
10
12
use syntax:: {
11
13
ast:: { self , HasLoopBody } ,
12
14
match_ast, AstNode ,
13
- SyntaxKind :: { IDENT , INT_NUMBER } ,
15
+ SyntaxKind :: { self , IDENT , INT_NUMBER } ,
14
16
SyntaxNode , SyntaxToken , TextRange , T ,
15
17
} ;
16
18
@@ -66,7 +68,9 @@ pub(crate) fn highlight_related(
66
68
T ! [ for ] if config. break_points && token. parent ( ) . and_then ( ast:: ForExpr :: cast) . is_some ( ) => {
67
69
highlight_break_points ( token)
68
70
}
69
- T ! [ break ] | T ! [ loop ] | T ! [ while ] if config. break_points => highlight_break_points ( token) ,
71
+ T ! [ break ] | T ! [ loop ] | T ! [ while ] | T ! [ continue ] if config. break_points => {
72
+ highlight_break_points ( token)
73
+ }
70
74
_ if config. references => highlight_references ( sema, & syntax, token, file_id) ,
71
75
_ => None ,
72
76
}
@@ -187,6 +191,7 @@ fn highlight_exit_points(
187
191
188
192
fn highlight_break_points ( token : SyntaxToken ) -> Option < Vec < HighlightedRange > > {
189
193
fn hl (
194
+ cursor_token_kind : SyntaxKind ,
190
195
token : Option < SyntaxToken > ,
191
196
label : Option < ast:: Label > ,
192
197
body : Option < ast:: StmtList > ,
@@ -197,11 +202,23 @@ fn highlight_break_points(token: SyntaxToken) -> Option<Vec<HighlightedRange>> {
197
202
label. as_ref ( ) . map ( |it| it. syntax ( ) . text_range ( ) ) ,
198
203
) ;
199
204
highlights. extend ( range. map ( |range| HighlightedRange { category : None , range } ) ) ;
200
- for_each_break_expr ( label, body, & mut |break_| {
201
- let range = cover_range (
202
- break_. break_token ( ) . map ( |it| it. text_range ( ) ) ,
203
- break_. lifetime ( ) . map ( |it| it. syntax ( ) . text_range ( ) ) ,
204
- ) ;
205
+ for_each_break_and_continue_expr ( label, body, & mut |expr| {
206
+ let range: Option < TextRange > = match ( cursor_token_kind, expr) {
207
+ ( T ! [ for ] | T ! [ while ] | T ! [ loop ] | T ! [ break ] , ast:: Expr :: BreakExpr ( break_) ) => {
208
+ cover_range (
209
+ break_. break_token ( ) . map ( |it| it. text_range ( ) ) ,
210
+ break_. lifetime ( ) . map ( |it| it. syntax ( ) . text_range ( ) ) ,
211
+ )
212
+ }
213
+ (
214
+ T ! [ for ] | T ! [ while ] | T ! [ loop ] | T ! [ continue ] ,
215
+ ast:: Expr :: ContinueExpr ( continue_) ,
216
+ ) => cover_range (
217
+ continue_. continue_token ( ) . map ( |it| it. text_range ( ) ) ,
218
+ continue_. lifetime ( ) . map ( |it| it. syntax ( ) . text_range ( ) ) ,
219
+ ) ,
220
+ _ => None ,
221
+ } ;
205
222
highlights. extend ( range. map ( |range| HighlightedRange { category : None , range } ) ) ;
206
223
} ) ;
207
224
Some ( highlights)
@@ -210,6 +227,7 @@ fn highlight_break_points(token: SyntaxToken) -> Option<Vec<HighlightedRange>> {
210
227
let lbl = match_ast ! {
211
228
match parent {
212
229
ast:: BreakExpr ( b) => b. lifetime( ) ,
230
+ ast:: ContinueExpr ( c) => c. lifetime( ) ,
213
231
ast:: LoopExpr ( l) => l. label( ) . and_then( |it| it. lifetime( ) ) ,
214
232
ast:: ForExpr ( f) => f. label( ) . and_then( |it| it. lifetime( ) ) ,
215
233
ast:: WhileExpr ( w) => w. label( ) . and_then( |it| it. lifetime( ) ) ,
@@ -224,19 +242,29 @@ fn highlight_break_points(token: SyntaxToken) -> Option<Vec<HighlightedRange>> {
224
242
}
225
243
None => true ,
226
244
} ;
245
+ let token_kind = token. kind ( ) ;
227
246
for anc in token. ancestors ( ) . flat_map ( ast:: Expr :: cast) {
228
247
return match anc {
229
- ast:: Expr :: LoopExpr ( l) if label_matches ( l. label ( ) ) => {
230
- hl ( l. loop_token ( ) , l. label ( ) , l. loop_body ( ) . and_then ( |it| it. stmt_list ( ) ) )
231
- }
232
- ast:: Expr :: ForExpr ( f) if label_matches ( f. label ( ) ) => {
233
- hl ( f. for_token ( ) , f. label ( ) , f. loop_body ( ) . and_then ( |it| it. stmt_list ( ) ) )
234
- }
235
- ast:: Expr :: WhileExpr ( w) if label_matches ( w. label ( ) ) => {
236
- hl ( w. while_token ( ) , w. label ( ) , w. loop_body ( ) . and_then ( |it| it. stmt_list ( ) ) )
237
- }
248
+ ast:: Expr :: LoopExpr ( l) if label_matches ( l. label ( ) ) => hl (
249
+ token_kind,
250
+ l. loop_token ( ) ,
251
+ l. label ( ) ,
252
+ l. loop_body ( ) . and_then ( |it| it. stmt_list ( ) ) ,
253
+ ) ,
254
+ ast:: Expr :: ForExpr ( f) if label_matches ( f. label ( ) ) => hl (
255
+ token_kind,
256
+ f. for_token ( ) ,
257
+ f. label ( ) ,
258
+ f. loop_body ( ) . and_then ( |it| it. stmt_list ( ) ) ,
259
+ ) ,
260
+ ast:: Expr :: WhileExpr ( w) if label_matches ( w. label ( ) ) => hl (
261
+ token_kind,
262
+ w. while_token ( ) ,
263
+ w. label ( ) ,
264
+ w. loop_body ( ) . and_then ( |it| it. stmt_list ( ) ) ,
265
+ ) ,
238
266
ast:: Expr :: BlockExpr ( e) if e. label ( ) . is_some ( ) && label_matches ( e. label ( ) ) => {
239
- hl ( None , e. label ( ) , e. stmt_list ( ) )
267
+ hl ( token_kind , None , e. label ( ) , e. stmt_list ( ) )
240
268
}
241
269
_ => continue ,
242
270
} ;
@@ -804,6 +832,115 @@ fn foo() {
804
832
) ;
805
833
}
806
834
835
+ #[ test]
836
+ fn test_hl_break_for_but_not_continue ( ) {
837
+ check (
838
+ r#"
839
+ fn foo() {
840
+ 'outer: for _ in () {
841
+ // ^^^^^^^^^^^
842
+ break;
843
+ // ^^^^^
844
+ continue;
845
+ 'inner: for _ in () {
846
+ break;
847
+ continue;
848
+ 'innermost: for _ in () {
849
+ continue 'outer;
850
+ break 'outer;
851
+ // ^^^^^^^^^^^^
852
+ continue 'inner;
853
+ break 'inner;
854
+ }
855
+ break$0 'outer;
856
+ // ^^^^^^^^^^^^
857
+ continue 'outer;
858
+ break;
859
+ continue;
860
+ }
861
+ break;
862
+ // ^^^^^
863
+ continue;
864
+ }
865
+ }
866
+ "# ,
867
+ ) ;
868
+ }
869
+
870
+ #[ test]
871
+ fn test_hl_continue_for_but_not_break ( ) {
872
+ check (
873
+ r#"
874
+ fn foo() {
875
+ 'outer: for _ in () {
876
+ // ^^^^^^^^^^^
877
+ break;
878
+ continue;
879
+ // ^^^^^^^^
880
+ 'inner: for _ in () {
881
+ break;
882
+ continue;
883
+ 'innermost: for _ in () {
884
+ continue 'outer;
885
+ // ^^^^^^^^^^^^^^^
886
+ break 'outer;
887
+ continue 'inner;
888
+ break 'inner;
889
+ }
890
+ break 'outer;
891
+ continue$0 'outer;
892
+ // ^^^^^^^^^^^^^^^
893
+ break;
894
+ continue;
895
+ }
896
+ break;
897
+ continue;
898
+ // ^^^^^^^^
899
+ }
900
+ }
901
+ "# ,
902
+ ) ;
903
+ }
904
+
905
+ #[ test]
906
+ fn test_hl_break_and_continue ( ) {
907
+ check (
908
+ r#"
909
+ fn foo() {
910
+ 'outer: fo$0r _ in () {
911
+ // ^^^^^^^^^^^
912
+ break;
913
+ // ^^^^^
914
+ continue;
915
+ // ^^^^^^^^
916
+ 'inner: for _ in () {
917
+ break;
918
+ continue;
919
+ 'innermost: for _ in () {
920
+ continue 'outer;
921
+ // ^^^^^^^^^^^^^^^
922
+ break 'outer;
923
+ // ^^^^^^^^^^^^
924
+ continue 'inner;
925
+ break 'inner;
926
+ }
927
+ break 'outer;
928
+ // ^^^^^^^^^^^^
929
+ continue 'outer;
930
+ // ^^^^^^^^^^^^^^^
931
+ break;
932
+ continue;
933
+ }
934
+ break;
935
+ // ^^^^^
936
+ continue;
937
+ // ^^^^^^^^
938
+ }
939
+ }
940
+ "# ,
941
+ ) ;
942
+ }
943
+
807
944
#[ test]
808
945
fn test_hl_break_while ( ) {
809
946
check (
0 commit comments