@@ -1314,12 +1314,13 @@ module ts {
13141314
13151315 function isAnyFunction ( node : Node ) : boolean {
13161316 switch ( node . kind ) {
1317+ case SyntaxKind . FunctionExpression :
13171318 case SyntaxKind . FunctionDeclaration :
1319+ case SyntaxKind . ArrowFunction :
13181320 case SyntaxKind . Method :
1319- case SyntaxKind . FunctionExpression :
13201321 case SyntaxKind . GetAccessor :
13211322 case SyntaxKind . SetAccessor :
1322- case SyntaxKind . ArrowFunction :
1323+ case SyntaxKind . Constructor :
13231324 return true ;
13241325 }
13251326 return false ;
@@ -1933,7 +1934,9 @@ module ts {
19331934 current = child ;
19341935 continue outer;
19351936 }
1936- if ( child . end > position ) break ;
1937+ if ( child . end > position ) {
1938+ break ;
1939+ }
19371940 }
19381941 return current ;
19391942 }
@@ -2160,13 +2163,143 @@ module ts {
21602163 return undefined ;
21612164 }
21622165
2163- if ( node . kind !== SyntaxKind . Identifier &&
2164- ! isLiteralNameOfPropertyDeclarationOrIndexAccess ( node ) &&
2165- ! isNameOfExternalModuleImportOrDeclaration ( node ) ) {
2166+ if ( node . kind === SyntaxKind . Identifier || isLiteralNameOfPropertyDeclarationOrIndexAccess ( node ) || isNameOfExternalModuleImportOrDeclaration ( node ) ) {
2167+ return getReferencesForNode ( node , [ sourceFile ] ) ;
2168+ }
2169+
2170+ switch ( node . kind ) {
2171+ case SyntaxKind . TryKeyword :
2172+ case SyntaxKind . CatchKeyword :
2173+ case SyntaxKind . FinallyKeyword :
2174+ if ( hasKind ( parent ( parent ( node ) ) , SyntaxKind . TryStatement ) ) {
2175+ return getTryCatchFinallyOccurrences ( < TryStatement > node . parent . parent ) ;
2176+ }
2177+ break ;
2178+ case SyntaxKind . SwitchKeyword :
2179+ if ( hasKind ( node . parent , SyntaxKind . SwitchStatement ) ) {
2180+ return getSwitchCaseDefaultOccurrences ( < SwitchStatement > node . parent ) ;
2181+ }
2182+ break ;
2183+ case SyntaxKind . CaseKeyword :
2184+ case SyntaxKind . DefaultKeyword :
2185+ if ( hasKind ( parent ( parent ( node ) ) , SyntaxKind . SwitchStatement ) ) {
2186+ return getSwitchCaseDefaultOccurrences ( < SwitchStatement > node . parent . parent ) ;
2187+ }
2188+ break ;
2189+ case SyntaxKind . BreakKeyword :
2190+ if ( hasKind ( node . parent , SyntaxKind . BreakStatement ) ) {
2191+ return getBreakStatementOccurences ( < BreakOrContinueStatement > node . parent ) ;
2192+ }
2193+ break ;
2194+ }
2195+
2196+ return undefined ;
2197+
2198+ function getTryCatchFinallyOccurrences ( tryStatement : TryStatement ) : ReferenceEntry [ ] {
2199+ var keywords : Node [ ] = [ ] ;
2200+
2201+ pushKeywordIf ( keywords , tryStatement . getFirstToken ( ) , SyntaxKind . TryKeyword ) ;
2202+
2203+ if ( tryStatement . catchBlock ) {
2204+ pushKeywordIf ( keywords , tryStatement . catchBlock . getFirstToken ( ) , SyntaxKind . CatchKeyword ) ;
2205+ }
2206+
2207+ if ( tryStatement . finallyBlock ) {
2208+ pushKeywordIf ( keywords , tryStatement . finallyBlock . getFirstToken ( ) , SyntaxKind . FinallyKeyword ) ;
2209+ }
2210+
2211+ return keywordsToReferenceEntries ( keywords ) ;
2212+ }
2213+
2214+ function getSwitchCaseDefaultOccurrences ( switchStatement : SwitchStatement ) {
2215+ var keywords : Node [ ] = [ ] ;
2216+
2217+ pushKeywordIf ( keywords , switchStatement . getFirstToken ( ) , SyntaxKind . SwitchKeyword ) ;
2218+
2219+ // Go through each clause in the switch statement, collecting the clause keywords.
2220+ forEach ( switchStatement . clauses , clause => {
2221+ pushKeywordIf ( keywords , clause . getFirstToken ( ) , SyntaxKind . CaseKeyword , SyntaxKind . DefaultKeyword ) ;
2222+
2223+ // For each clause, also recursively traverse the statements where we can find analogous breaks.
2224+ forEachChild ( clause , function aggregateBreakKeywords ( node : Node ) : void {
2225+ switch ( node . kind ) {
2226+ case SyntaxKind . BreakStatement :
2227+ // If the break statement has a label, it cannot be part of a switch block.
2228+ if ( ! ( < BreakOrContinueStatement > node ) . label ) {
2229+ pushKeywordIf ( keywords , node . getFirstToken ( ) , SyntaxKind . BreakKeyword ) ;
2230+ }
2231+ // Fall through
2232+ case SyntaxKind . ForStatement :
2233+ case SyntaxKind . ForInStatement :
2234+ case SyntaxKind . DoStatement :
2235+ case SyntaxKind . WhileStatement :
2236+ case SyntaxKind . SwitchStatement :
2237+ return ;
2238+ }
2239+
2240+ // Do not cross function boundaries.
2241+ if ( ! isAnyFunction ( node ) ) {
2242+ forEachChild ( node , aggregateBreakKeywords ) ;
2243+ }
2244+ } ) ;
2245+ } ) ;
2246+
2247+ return keywordsToReferenceEntries ( keywords ) ;
2248+ }
2249+
2250+ function getBreakStatementOccurences ( breakStatement : BreakOrContinueStatement ) : ReferenceEntry [ ] {
2251+ // TODO (drosen): Deal with labeled statements.
2252+ if ( breakStatement . label ) {
2253+ return undefined ;
2254+ }
2255+
2256+ for ( var owner = node . parent ; owner ; owner = owner . parent ) {
2257+ switch ( owner . kind ) {
2258+ case SyntaxKind . ForStatement :
2259+ case SyntaxKind . ForInStatement :
2260+ case SyntaxKind . DoStatement :
2261+ case SyntaxKind . WhileStatement :
2262+ // TODO (drosen): Handle loops!
2263+ return undefined ;
2264+
2265+ case SyntaxKind . SwitchStatement :
2266+ return getSwitchCaseDefaultOccurrences ( < SwitchStatement > owner ) ;
2267+
2268+ default :
2269+ if ( isAnyFunction ( owner ) ) {
2270+ return undefined ;
2271+ }
2272+ }
2273+ }
2274+
21662275 return undefined ;
21672276 }
21682277
2169- return getReferencesForNode ( node , [ sourceFile ] ) ;
2278+ // returns true if 'node' is defined and has a matching 'kind'.
2279+ function hasKind ( node : Node , kind : SyntaxKind ) {
2280+ return ! ! ( node && node . kind === kind ) ;
2281+ }
2282+
2283+ // Null-propagating 'parent' function.
2284+ function parent ( node : Node ) : Node {
2285+ return node && node . parent ;
2286+ }
2287+
2288+ function pushKeywordIf ( keywordList : Node [ ] , token : Node , ...expected : SyntaxKind [ ] ) : void {
2289+ if ( ! token ) {
2290+ return ;
2291+ }
2292+
2293+ if ( contains ( < SyntaxKind [ ] > expected , token . kind ) ) {
2294+ keywordList . push ( token ) ;
2295+ }
2296+ }
2297+
2298+ function keywordsToReferenceEntries ( keywords : Node [ ] ) : ReferenceEntry [ ] {
2299+ return map ( keywords , keyword =>
2300+ new ReferenceEntry ( filename , TypeScript . TextSpan . fromBounds ( keyword . getStart ( ) , keyword . end ) , /* isWriteAccess */ false )
2301+ ) ;
2302+ }
21702303 }
21712304
21722305 function getReferencesAtPosition ( filename : string , position : number ) : ReferenceEntry [ ] {
@@ -2284,13 +2417,13 @@ module ts {
22842417 var container = getContainerNode ( declarations [ i ] ) ;
22852418
22862419 if ( scope && scope !== container ) {
2287- // Diffrent declarations have diffrent containers, bail out
2420+ // Different declarations have different containers, bail out
22882421 return undefined ;
22892422 }
22902423
22912424 if ( container . kind === SyntaxKind . SourceFile && ! isExternalModule ( < SourceFile > container ) ) {
22922425 // This is a global variable and not an external module, any declaration defined
2293- // withen this scope is visible outside the file
2426+ // within this scope is visible outside the file
22942427 return undefined ;
22952428 }
22962429
@@ -2957,7 +3090,7 @@ module ts {
29573090 // ["// hack 1", "// ", "hack 1", undefined, "hack"]
29583091 //
29593092 // Here are the relevant capture groups:
2960- // 0) The full match for hte entire regex.
3093+ // 0) The full match for the entire regex.
29613094 // 1) The preamble to the message portion.
29623095 // 2) The message portion.
29633096 // 3...N) The descriptor that was matched - by index. 'undefined' for each
0 commit comments