@@ -1296,8 +1296,12 @@ module ts {
1296
1296
( < LabelledStatement > node . parent ) . label === node ;
1297
1297
}
1298
1298
1299
+ /**
1300
+ * Whether or not a 'node' is preceded by a label of the given string.
1301
+ * Note: 'node' cannot be a SourceFile.
1302
+ */
1299
1303
function isLabelledBy ( node : Node , labelName : string ) {
1300
- for ( var owner = node . parent ; owner && owner . kind === SyntaxKind . LabelledStatement ; owner = owner . parent ) {
1304
+ for ( var owner = node . parent ; owner . kind === SyntaxKind . LabelledStatement ; owner = owner . parent ) {
1301
1305
if ( ( < LabelledStatement > owner ) . label . text === labelName ) {
1302
1306
return true ;
1303
1307
}
@@ -2326,43 +2330,12 @@ module ts {
2326
2330
}
2327
2331
}
2328
2332
}
2329
-
2330
- // These track whether we can own unlabeled break/continues.
2331
- var breakSearchType = BreakContinueSearchType . All ;
2332
- var continueSearchType = BreakContinueSearchType . All ;
2333
2333
2334
- ( function aggregateBreakContinues ( node : Node ) {
2335
- // Remember the statuses of the flags before diving into the next node.
2336
- var prevBreakSearchType = breakSearchType ;
2337
- var prevContinueSearchType = continueSearchType ;
2338
-
2339
- switch ( node . kind ) {
2340
- case SyntaxKind . BreakStatement :
2341
- case SyntaxKind . ContinueStatement :
2342
- if ( ownsBreakOrContinue ( loopNode , < BreakOrContinueStatement > node , breakSearchType , continueSearchType ) ) {
2343
- pushKeywordIf ( keywords , node . getFirstToken ( ) , SyntaxKind . BreakKeyword , SyntaxKind . ContinueKeyword ) ;
2344
- }
2345
- break ;
2346
-
2347
- case SyntaxKind . ForStatement :
2348
- case SyntaxKind . ForInStatement :
2349
- case SyntaxKind . DoStatement :
2350
- case SyntaxKind . WhileStatement :
2351
- continueSearchType = BreakContinueSearchType . Labeled ;
2352
- // Fall through
2353
- case SyntaxKind . SwitchStatement :
2354
- breakSearchType = BreakContinueSearchType . Labeled ;
2355
- }
2356
-
2357
- // Do not cross function boundaries.
2358
- if ( ! isAnyFunction ( node ) ) {
2359
- forEachChild ( node , aggregateBreakContinues ) ;
2360
- }
2361
-
2362
- // Restore the last state.
2363
- breakSearchType = prevBreakSearchType ;
2364
- continueSearchType = prevContinueSearchType ;
2365
- } ) ( loopNode . statement ) ;
2334
+ aggregateBreakAndContinueKeywords ( /* owner */ loopNode ,
2335
+ /* startPoint */ loopNode . statement ,
2336
+ /* breakSearchType */ BreakContinueSearchType . All ,
2337
+ /* continueSearchType */ BreakContinueSearchType . All ,
2338
+ /* keywordAccumulator */ keywords ) ;
2366
2339
2367
2340
return map ( keywords , getReferenceEntryFromNode ) ;
2368
2341
}
@@ -2375,41 +2348,16 @@ module ts {
2375
2348
// Types of break statements we can grab on to.
2376
2349
var breakSearchType = BreakContinueSearchType . All ;
2377
2350
2378
- // Go through each clause in the switch statement, collecting the case/ default keywords.
2351
+ // Go through each clause in the switch statement, collecting the ' case'/' default' keywords.
2379
2352
forEach ( switchStatement . clauses , clause => {
2380
2353
pushKeywordIf ( keywords , clause . getFirstToken ( ) , SyntaxKind . CaseKeyword , SyntaxKind . DefaultKeyword ) ;
2381
2354
2382
- // For each clause, also recursively traverse the statements where we can find analogous breaks.
2383
- forEachChild ( clause , function aggregateBreakKeywords ( node : Node ) : void {
2384
- // Back the old search value up.
2385
- var oldBreakSearchType = breakSearchType ;
2386
-
2387
- switch ( node . kind ) {
2388
- case SyntaxKind . BreakStatement :
2389
- // If the break statement has a label, it cannot be part of a switch block.
2390
- if ( ownsBreakOrContinue ( switchStatement ,
2391
- < BreakOrContinueStatement > node ,
2392
- breakSearchType ,
2393
- /*continuesSearchType*/ BreakContinueSearchType . None ) ) {
2394
- pushKeywordIf ( keywords , node . getFirstToken ( ) , SyntaxKind . BreakKeyword ) ;
2395
- }
2396
- break ;
2397
- case SyntaxKind . ForStatement :
2398
- case SyntaxKind . ForInStatement :
2399
- case SyntaxKind . DoStatement :
2400
- case SyntaxKind . WhileStatement :
2401
- case SyntaxKind . SwitchStatement :
2402
- breakSearchType = BreakContinueSearchType . Labeled ;
2403
- }
2404
-
2405
- // Do not cross function boundaries.
2406
- if ( ! isAnyFunction ( node ) ) {
2407
- forEachChild ( node , aggregateBreakKeywords ) ;
2408
- }
2409
-
2410
- // Restore the last state.
2411
- breakSearchType = oldBreakSearchType ;
2412
- } ) ;
2355
+ // For each clause, aggregate each of the analogous 'break' statements.
2356
+ aggregateBreakAndContinueKeywords ( /* owner */ switchStatement ,
2357
+ /* startPoint */ clause ,
2358
+ /* breakSearchType */ BreakContinueSearchType . All ,
2359
+ /* continueSearchType */ BreakContinueSearchType . None ,
2360
+ /* keywordAccumulator */ keywords ) ;
2413
2361
} ) ;
2414
2362
2415
2363
return map ( keywords , getReferenceEntryFromNode ) ;
@@ -2445,19 +2393,63 @@ module ts {
2445
2393
return undefined ;
2446
2394
}
2447
2395
2396
+ function aggregateBreakAndContinueKeywords ( owner : Node ,
2397
+ startPoint : Node ,
2398
+ breakSearchType : BreakContinueSearchType ,
2399
+ continueSearchType : BreakContinueSearchType ,
2400
+ keywordAccumulator : Node [ ] ) : void {
2401
+ ( function aggregate ( node : Node ) {
2402
+ // Remember the statuses of the flags before diving into the next node.
2403
+ var prevBreakSearchType = breakSearchType ;
2404
+ var prevContinueSearchType = continueSearchType ;
2405
+
2406
+ switch ( node . kind ) {
2407
+ case SyntaxKind . BreakStatement :
2408
+ case SyntaxKind . ContinueStatement :
2409
+ if ( ownsBreakOrContinue ( owner , < BreakOrContinueStatement > node , breakSearchType , continueSearchType ) ) {
2410
+ pushKeywordIf ( keywordAccumulator , node . getFirstToken ( ) , SyntaxKind . BreakKeyword , SyntaxKind . ContinueKeyword ) ;
2411
+ }
2412
+ break ;
2413
+
2414
+ case SyntaxKind . ForStatement :
2415
+ case SyntaxKind . ForInStatement :
2416
+ case SyntaxKind . DoStatement :
2417
+ case SyntaxKind . WhileStatement :
2418
+ // Inner loops take ownership of unlabeled 'continue' statements.
2419
+ continueSearchType &= ~ BreakContinueSearchType . Unlabeled ;
2420
+ // Fall through
2421
+ case SyntaxKind . SwitchStatement :
2422
+ // Inner loops & 'switch' statements take ownership of unlabeled 'break' statements.
2423
+ breakSearchType &= ~ BreakContinueSearchType . Unlabeled ;
2424
+ break ;
2425
+ }
2426
+
2427
+ // Do not cross function boundaries.
2428
+ if ( ! isAnyFunction ( node ) ) {
2429
+ forEachChild ( node , aggregate ) ;
2430
+ }
2431
+
2432
+ // Restore the last state.
2433
+ breakSearchType = prevBreakSearchType ;
2434
+ continueSearchType = prevContinueSearchType ;
2435
+ } ) ( startPoint ) ;
2436
+
2437
+ return ;
2438
+ }
2439
+
2448
2440
// Note: 'statement' must be a descendant of 'root'.
2449
2441
// Reasonable logic for restricting traversal prior to arriving at the
2450
2442
// 'statement' node is beyond the scope of this function.
2451
- function ownsBreakOrContinue ( root : Node ,
2443
+ function ownsBreakOrContinue ( owner : Node ,
2452
2444
statement : BreakOrContinueStatement ,
2453
2445
breakSearchType : BreakContinueSearchType ,
2454
2446
continueSearchType : BreakContinueSearchType ) : boolean {
2455
2447
var searchType = statement . kind === SyntaxKind . BreakStatement ?
2456
2448
breakSearchType :
2457
2449
continueSearchType ;
2458
2450
2459
- if ( statement . label ) {
2460
- return isLabelledBy ( root , statement . label . text ) ;
2451
+ if ( statement . label && ( searchType & BreakContinueSearchType . Labeled ) ) {
2452
+ return isLabelledBy ( owner , statement . label . text ) ;
2461
2453
}
2462
2454
else {
2463
2455
return ! ! ( searchType & BreakContinueSearchType . Unlabeled ) ;
@@ -2817,7 +2809,7 @@ module ts {
2817
2809
if ( isExternalModule ( < SourceFile > searchSpaceNode ) ) {
2818
2810
return undefined ;
2819
2811
}
2820
- // Fall through
2812
+ // Fall through
2821
2813
case SyntaxKind . FunctionDeclaration :
2822
2814
case SyntaxKind . FunctionExpression :
2823
2815
break ;
0 commit comments