@@ -2038,15 +2038,6 @@ module ts {
20382038 return ( SyntaxKind . FirstPunctuation <= kind && kind <= SyntaxKind . LastPunctuation ) ;
20392039 }
20402040
2041- function isVisibleWithinClassDeclaration ( symbol : Symbol , containingClass : Declaration ) : boolean {
2042- var declaration = symbol . declarations && symbol . declarations [ 0 ] ;
2043- if ( declaration && ( declaration . flags & NodeFlags . Private ) ) {
2044- var declarationClass = getAncestor ( declaration , SyntaxKind . ClassDeclaration ) ;
2045- return containingClass === declarationClass ;
2046- }
2047- return true ;
2048- }
2049-
20502041 function filterContextualMembersList ( contextualMemberSymbols : Symbol [ ] , existingMembers : Declaration [ ] ) : Symbol [ ] {
20512042 if ( ! existingMembers || existingMembers . length === 0 ) {
20522043 return contextualMemberSymbols ;
@@ -2150,15 +2141,14 @@ module ts {
21502141 // Right of dot member completion list
21512142 if ( isRightOfDot ) {
21522143 var symbols : Symbol [ ] = [ ] ;
2153- var containingClass = getAncestor ( mappedNode , SyntaxKind . ClassDeclaration ) ;
21542144 isMemberCompletion = true ;
21552145
21562146 if ( mappedNode . kind === SyntaxKind . Identifier || mappedNode . kind === SyntaxKind . QualifiedName || mappedNode . kind === SyntaxKind . PropertyAccess ) {
21572147 var symbol = typeInfoResolver . getSymbolInfo ( mappedNode ) ;
21582148 if ( symbol && symbol . flags & SymbolFlags . HasExports ) {
21592149 // Extract module or enum members
21602150 forEachValue ( symbol . exports , symbol => {
2161- if ( isVisibleWithinClassDeclaration ( symbol , containingClass ) ) {
2151+ if ( typeInfoResolver . isValidPropertyAccess ( < PropertyAccess > ( mappedNode . parent ) , symbol . name ) ) {
21622152 symbols . push ( symbol ) ;
21632153 }
21642154 } ) ;
@@ -2170,7 +2160,7 @@ module ts {
21702160 if ( apparentType ) {
21712161 // Filter private properties
21722162 forEach ( apparentType . getApparentProperties ( ) , symbol => {
2173- if ( isVisibleWithinClassDeclaration ( symbol , containingClass ) ) {
2163+ if ( typeInfoResolver . isValidPropertyAccess ( < PropertyAccess > ( mappedNode . parent ) , symbol . name ) ) {
21742164 symbols . push ( symbol ) ;
21752165 }
21762166 } ) ;
@@ -2645,6 +2635,11 @@ module ts {
26452635 return getReturnOccurrences ( < ReturnStatement > node . parent ) ;
26462636 }
26472637 break ;
2638+ case SyntaxKind . ThrowKeyword :
2639+ if ( hasKind ( node . parent , SyntaxKind . ThrowStatement ) ) {
2640+ return getThrowOccurrences ( < ThrowStatement > node . parent ) ;
2641+ }
2642+ break ;
26482643 case SyntaxKind . TryKeyword :
26492644 case SyntaxKind . CatchKeyword :
26502645 case SyntaxKind . FinallyKeyword :
@@ -2762,12 +2757,108 @@ module ts {
27622757 }
27632758
27642759 var keywords : Node [ ] = [ ]
2765- forEachReturnStatement ( < Block > ( < FunctionDeclaration > func ) . body , returnStatement => {
2760+ forEachReturnStatement ( < Block > func . body , returnStatement => {
27662761 pushKeywordIf ( keywords , returnStatement . getFirstToken ( ) , SyntaxKind . ReturnKeyword ) ;
27672762 } ) ;
27682763
2764+ // Include 'throw' statements that do not occur within a try block.
2765+ forEach ( aggregateOwnedThrowStatements ( func . body ) , throwStatement => {
2766+ pushKeywordIf ( keywords , throwStatement . getFirstToken ( ) , SyntaxKind . ThrowKeyword ) ;
2767+ } ) ;
2768+
27692769 return map ( keywords , getReferenceEntryFromNode ) ;
27702770 }
2771+
2772+ function getThrowOccurrences ( throwStatement : ThrowStatement ) {
2773+ var owner = getThrowStatementOwner ( throwStatement ) ;
2774+
2775+ if ( ! owner ) {
2776+ return undefined ;
2777+ }
2778+
2779+ var keywords : Node [ ] = [ ] ;
2780+
2781+ forEach ( aggregateOwnedThrowStatements ( owner ) , throwStatement => {
2782+ pushKeywordIf ( keywords , throwStatement . getFirstToken ( ) , SyntaxKind . ThrowKeyword ) ;
2783+ } ) ;
2784+
2785+ // If the "owner" is a function, then we equate 'return' and 'throw' statements in their
2786+ // ability to "jump out" of the function, and include occurrences for both.
2787+ if ( owner . kind === SyntaxKind . FunctionBlock ) {
2788+ forEachReturnStatement ( < Block > owner , returnStatement => {
2789+ pushKeywordIf ( keywords , returnStatement . getFirstToken ( ) , SyntaxKind . ReturnKeyword ) ;
2790+ } ) ;
2791+ }
2792+
2793+ return map ( keywords , getReferenceEntryFromNode ) ;
2794+ }
2795+
2796+ /**
2797+ * Aggregates all throw-statements within this node *without* crossing
2798+ * into function boundaries and try-blocks with catch-clauses.
2799+ */
2800+ function aggregateOwnedThrowStatements ( node : Node ) : ThrowStatement [ ] {
2801+ var statementAccumulator : ThrowStatement [ ] = [ ]
2802+ aggregate ( node ) ;
2803+ return statementAccumulator ;
2804+
2805+ function aggregate ( node : Node ) : void {
2806+ if ( node . kind === SyntaxKind . ThrowStatement ) {
2807+ statementAccumulator . push ( < ThrowStatement > node ) ;
2808+ }
2809+ else if ( node . kind === SyntaxKind . TryStatement ) {
2810+ var tryStatement = < TryStatement > node ;
2811+
2812+ if ( tryStatement . catchBlock ) {
2813+ aggregate ( tryStatement . catchBlock ) ;
2814+ }
2815+ else {
2816+ // Exceptions thrown within a try block lacking a catch clause
2817+ // are "owned" in the current context.
2818+ aggregate ( tryStatement . tryBlock ) ;
2819+ }
2820+
2821+ if ( tryStatement . finallyBlock ) {
2822+ aggregate ( tryStatement . finallyBlock ) ;
2823+ }
2824+ }
2825+ // Do not cross function boundaries.
2826+ else if ( ! isAnyFunction ( node ) ) {
2827+ forEachChild ( node , aggregate ) ;
2828+ }
2829+ } ;
2830+ }
2831+
2832+ /**
2833+ * For lack of a better name, this function takes a throw statement and returns the
2834+ * nearest ancestor that is a try-block (whose try statement has a catch clause),
2835+ * function-block, or source file.
2836+ */
2837+ function getThrowStatementOwner ( throwStatement : ThrowStatement ) : Node {
2838+ var child : Node = throwStatement ;
2839+
2840+ while ( child . parent ) {
2841+ var parent = child . parent ;
2842+
2843+ if ( parent . kind === SyntaxKind . FunctionBlock || parent . kind === SyntaxKind . SourceFile ) {
2844+ return parent ;
2845+ }
2846+
2847+ // A throw-statement is only owned by a try-statement if the try-statement has
2848+ // a catch clause, and if the throw-statement occurs within the try block.
2849+ if ( parent . kind === SyntaxKind . TryStatement ) {
2850+ var tryStatement = < TryStatement > parent ;
2851+
2852+ if ( tryStatement . tryBlock === child && tryStatement . catchBlock ) {
2853+ return child ;
2854+ }
2855+ }
2856+
2857+ child = parent ;
2858+ }
2859+
2860+ return undefined ;
2861+ }
27712862
27722863 function getTryCatchFinallyOccurrences ( tryStatement : TryStatement ) : ReferenceEntry [ ] {
27732864 var keywords : Node [ ] = [ ] ;
0 commit comments