@@ -2331,11 +2331,13 @@ module ts {
23312331 }
23322332 }
23332333
2334- aggregateBreakAndContinueKeywords ( /* owner */ loopNode ,
2335- /* startPoint */ loopNode . statement ,
2336- /* breakSearchType */ BreakContinueSearchType . All ,
2337- /* continueSearchType */ BreakContinueSearchType . All ,
2338- /* keywordAccumulator */ keywords ) ;
2334+ var breaksAndContinues = aggregateAllBreakAndContinueStatements ( loopNode . statement ) ;
2335+
2336+ forEach ( breaksAndContinues , statement => {
2337+ if ( ownsBreakOrContinueStatement ( loopNode , statement ) ) {
2338+ pushKeywordIf ( keywords , statement . getFirstToken ( ) , SyntaxKind . BreakKeyword , SyntaxKind . ContinueKeyword ) ;
2339+ }
2340+ } ) ;
23392341
23402342 return map ( keywords , getReferenceEntryFromNode ) ;
23412343 }
@@ -2352,109 +2354,85 @@ module ts {
23522354 forEach ( switchStatement . clauses , clause => {
23532355 pushKeywordIf ( keywords , clause . getFirstToken ( ) , SyntaxKind . CaseKeyword , SyntaxKind . DefaultKeyword ) ;
23542356
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 ) ;
2357+ var breaksAndContinues = aggregateAllBreakAndContinueStatements ( clause ) ;
2358+
2359+ forEach ( breaksAndContinues , statement => {
2360+ if ( ownsBreakOrContinueStatement ( switchStatement , statement ) ) {
2361+ pushKeywordIf ( keywords , statement . getFirstToken ( ) , SyntaxKind . BreakKeyword ) ;
2362+ }
2363+ } ) ;
23612364 } ) ;
23622365
23632366 return map ( keywords , getReferenceEntryFromNode ) ;
23642367 }
23652368
2366- function getBreakOrContinueStatementOccurences ( breakOrContinueStatement : BreakOrContinueStatement ) : ReferenceEntry [ ] {
2367- for ( var owner = node . parent ; owner ; owner = owner . parent ) {
2369+ function getBreakOrContinueStatementOccurences ( breakOrContinueStatement : BreakOrContinueStatement ) : ReferenceEntry [ ] {
2370+ var owner = getBreakOrContinueOwner ( breakOrContinueStatement ) ;
2371+
2372+ if ( owner ) {
23682373 switch ( owner . kind ) {
23692374 case SyntaxKind . ForStatement :
23702375 case SyntaxKind . ForInStatement :
23712376 case SyntaxKind . DoStatement :
23722377 case SyntaxKind . WhileStatement :
2373- // The iteration statement is the owner if the break/continue statement is either unlabeled,
2374- // or if the break/continue statement's label corresponds to one of the loop's labels.
2375- if ( ! breakOrContinueStatement . label || isLabeledBy ( owner , breakOrContinueStatement . label . text ) ) {
2376- return getLoopBreakContinueOccurrences ( < IterationStatement > owner )
2377- }
2378- break ;
2378+ return getLoopBreakContinueOccurrences ( < IterationStatement > owner )
23792379 case SyntaxKind . SwitchStatement :
2380- // A switch statement can only be the owner of an break statement.
2381- if ( breakOrContinueStatement . kind === SyntaxKind . BreakStatement && ( ! breakOrContinueStatement . label || isLabeledBy ( owner , breakOrContinueStatement . label . text ) ) ) {
2382- return getSwitchCaseDefaultOccurrences ( < SwitchStatement > owner ) ;
2383- }
2384- break ;
2385- default :
2386- if ( isAnyFunction ( owner ) ) {
2387- return undefined ;
2388- }
2389- break ;
2380+ return getSwitchCaseDefaultOccurrences ( < SwitchStatement > owner ) ;
2381+
23902382 }
23912383 }
23922384
23932385 return undefined ;
23942386 }
23952387
2396- function aggregateBreakAndContinueKeywords ( owner : Node ,
2397- startPoint : Node ,
2398- breakSearchType : BreakContinueSearchType ,
2399- continueSearchType : BreakContinueSearchType ,
2400- keywordAccumulator : Node [ ] ) : void {
2401-
2402- return aggregate ( startPoint ) ;
2388+ function aggregateAllBreakAndContinueStatements ( node : Node ) : BreakOrContinueStatement [ ] {
2389+ var statementAccumulator : BreakOrContinueStatement [ ] = [ ]
2390+ aggregate ( node ) ;
2391+ return statementAccumulator ;
24032392
24042393 function aggregate ( node : Node ) : void {
2405- // Remember the statuses of the flags before diving into the next node.
2406- var prevBreakSearchType = breakSearchType ;
2407- var prevContinueSearchType = continueSearchType ;
2408-
2409- switch ( node . kind ) {
2410- case SyntaxKind . BreakStatement :
2411- case SyntaxKind . ContinueStatement :
2412- if ( ownsBreakOrContinue ( owner , < BreakOrContinueStatement > node , breakSearchType , continueSearchType ) ) {
2413- pushKeywordIf ( keywordAccumulator , node . getFirstToken ( ) , SyntaxKind . BreakKeyword , SyntaxKind . ContinueKeyword ) ;
2414- }
2415- break ;
2416-
2417- case SyntaxKind . ForStatement :
2418- case SyntaxKind . ForInStatement :
2419- case SyntaxKind . DoStatement :
2420- case SyntaxKind . WhileStatement :
2421- // Inner loops take ownership of unlabeled 'continue' statements.
2422- continueSearchType &= ~ BreakContinueSearchType . Unlabeled ;
2423- // Fall through
2424- case SyntaxKind . SwitchStatement :
2425- // Inner loops & 'switch' statements take ownership of unlabeled 'break' statements.
2426- breakSearchType &= ~ BreakContinueSearchType . Unlabeled ;
2427- break ;
2394+ if ( node . kind === SyntaxKind . BreakStatement || node . kind === SyntaxKind . ContinueStatement ) {
2395+ statementAccumulator . push ( node ) ;
24282396 }
2429-
24302397 // Do not cross function boundaries.
2431- if ( ! isAnyFunction ( node ) ) {
2398+ else if ( ! isAnyFunction ( node ) ) {
24322399 forEachChild ( node , aggregate ) ;
24332400 }
2434-
2435- // Restore the last state.
2436- breakSearchType = prevBreakSearchType ;
2437- continueSearchType = prevContinueSearchType ;
24382401 } ;
24392402 }
24402403
2441- // Note: 'statement' must be a descendant of 'root'.
2442- // Reasonable logic for restricting traversal prior to arriving at the
2443- // 'statement' node is beyond the scope of this function.
2444- function ownsBreakOrContinue ( owner : Node ,
2445- statement : BreakOrContinueStatement ,
2446- breakSearchType : BreakContinueSearchType ,
2447- continueSearchType : BreakContinueSearchType ) : boolean {
2448- var searchType = statement . kind === SyntaxKind . BreakStatement ?
2449- breakSearchType :
2450- continueSearchType ;
2404+ function ownsBreakOrContinueStatement ( owner : Node , statement : BreakOrContinueStatement ) : boolean {
2405+ var actualOwner = getBreakOrContinueOwner ( statement ) ;
24512406
2452- if ( statement . label && ( searchType & BreakContinueSearchType . Labeled ) ) {
2453- return isLabeledBy ( owner , statement . label . text ) ;
2454- }
2455- else {
2456- return ! ! ( searchType & BreakContinueSearchType . Unlabeled ) ;
2407+ return actualOwner && actualOwner === owner ;
2408+ }
2409+
2410+ function getBreakOrContinueOwner ( statement : BreakOrContinueStatement ) : Node {
2411+ for ( var node = statement . parent ; node ; node = node . parent ) {
2412+ switch ( node . kind ) {
2413+ case SyntaxKind . SwitchStatement :
2414+ if ( statement . kind === SyntaxKind . ContinueStatement ) {
2415+ continue ;
2416+ }
2417+ // Fall through.
2418+ case SyntaxKind . ForStatement :
2419+ case SyntaxKind . ForInStatement :
2420+ case SyntaxKind . WhileStatement :
2421+ case SyntaxKind . DoStatement :
2422+ if ( ! statement . label || isLabeledBy ( node , statement . label . text ) ) {
2423+ return node ;
2424+ }
2425+ break ;
2426+ default :
2427+ // Don't cross function boundaries.
2428+ if ( isAnyFunction ( node ) ) {
2429+ return undefined ;
2430+ }
2431+ break ;
2432+ }
24572433 }
2434+
2435+ return undefined ;
24582436 }
24592437
24602438 // returns true if 'node' is defined and has a matching 'kind'.
0 commit comments