@@ -119,6 +119,7 @@ namespace ts {
119
119
let languageVersion : ScriptTarget ;
120
120
let parent : Node ;
121
121
let container : Node ;
122
+ let containerContainer : Node ; // Container one level up
122
123
let blockScopeContainer : Node ;
123
124
let inferenceContainer : Node ;
124
125
let lastContainer : Node ;
@@ -187,6 +188,7 @@ namespace ts {
187
188
languageVersion = undefined ;
188
189
parent = undefined ;
189
190
container = undefined ;
191
+ containerContainer = undefined ;
190
192
blockScopeContainer = undefined ;
191
193
inferenceContainer = undefined ;
192
194
lastContainer = undefined ;
@@ -224,13 +226,7 @@ namespace ts {
224
226
symbol . flags |= symbolFlags ;
225
227
226
228
node . symbol = symbol ;
227
-
228
- if ( ! symbol . declarations ) {
229
- symbol . declarations = [ node ] ;
230
- }
231
- else {
232
- symbol . declarations . push ( node ) ;
233
- }
229
+ symbol . declarations = append ( symbol . declarations , node ) ;
234
230
235
231
if ( symbolFlags & SymbolFlags . HasExports && ! symbol . exports ) {
236
232
symbol . exports = createSymbolTable ( ) ;
@@ -486,8 +482,11 @@ namespace ts {
486
482
// and block-container. Then after we pop out of processing the children, we restore
487
483
// these saved values.
488
484
const saveContainer = container ;
485
+ const saveContainerContainer = containerContainer ;
489
486
const savedBlockScopeContainer = blockScopeContainer ;
490
487
488
+ containerContainer = container ;
489
+
491
490
// Depending on what kind of node this is, we may have to adjust the current container
492
491
// and block-container. If the current node is a container, then it is automatically
493
492
// considered the current block-container as well. Also, for containers that we know
@@ -580,7 +579,9 @@ namespace ts {
580
579
else {
581
580
bindChildren ( node ) ;
582
581
}
582
+
583
583
container = saveContainer ;
584
+ containerContainer = saveContainerContainer ;
584
585
blockScopeContainer = savedBlockScopeContainer ;
585
586
}
586
587
@@ -2327,14 +2328,23 @@ namespace ts {
2327
2328
2328
2329
function bindThisPropertyAssignment ( node : BinaryExpression | PropertyAccessExpression ) {
2329
2330
Debug . assert ( isInJavaScriptFile ( node ) ) ;
2330
- const container = getThisContainer ( node , /*includeArrowFunctions*/ false ) ;
2331
- switch ( container . kind ) {
2331
+ const thisContainer = getThisContainer ( node , /*includeArrowFunctions*/ false ) ;
2332
+ switch ( thisContainer . kind ) {
2332
2333
case SyntaxKind . FunctionDeclaration :
2333
2334
case SyntaxKind . FunctionExpression :
2335
+ let constructorSymbol = thisContainer . symbol ;
2336
+ // For `f.prototype.m = function() { this.x = 0; }`, `this.x = 0` should modify `f`'s members, not the function expression.
2337
+ if ( isBinaryExpression ( thisContainer . parent ) && thisContainer . parent . operatorToken . kind === SyntaxKind . EqualsToken ) {
2338
+ const l = thisContainer . parent . left ;
2339
+ if ( isPropertyAccessExpression ( l ) && isPropertyAccessExpression ( l . expression ) && l . expression . name . escapedText === "prototype" && isEntityNameExpression ( l . expression . expression ) ) {
2340
+ constructorSymbol = getJSInitializerSymbolFromName ( l . expression . expression , containerContainer ) ;
2341
+ }
2342
+ }
2343
+
2334
2344
// Declare a 'member' if the container is an ES5 class or ES6 constructor
2335
- container . symbol . members = container . symbol . members || createSymbolTable ( ) ;
2345
+ constructorSymbol . members = constructorSymbol . members || createSymbolTable ( ) ;
2336
2346
// It's acceptable for multiple 'this' assignments of the same identifier to occur
2337
- declareSymbol ( container . symbol . members , container . symbol , node , SymbolFlags . Property , SymbolFlags . PropertyExcludes & ~ SymbolFlags . Property ) ;
2347
+ declareSymbol ( constructorSymbol . members , constructorSymbol , node , SymbolFlags . Property , SymbolFlags . PropertyExcludes & ~ SymbolFlags . Property ) ;
2338
2348
break ;
2339
2349
2340
2350
case SyntaxKind . Constructor :
@@ -2344,10 +2354,13 @@ namespace ts {
2344
2354
case SyntaxKind . SetAccessor :
2345
2355
// this.foo assignment in a JavaScript class
2346
2356
// Bind this property to the containing class
2347
- const containingClass = container . parent ;
2348
- const symbolTable = hasModifier ( container , ModifierFlags . Static ) ? containingClass . symbol . exports : containingClass . symbol . members ;
2357
+ const containingClass = thisContainer . parent ;
2358
+ const symbolTable = hasModifier ( thisContainer , ModifierFlags . Static ) ? containingClass . symbol . exports : containingClass . symbol . members ;
2349
2359
declareSymbol ( symbolTable , containingClass . symbol , node , SymbolFlags . Property , SymbolFlags . None , /*isReplaceableByMethod*/ true ) ;
2350
2360
break ;
2361
+
2362
+ default :
2363
+ Debug . fail ( Debug . showSyntaxKind ( thisContainer ) ) ;
2351
2364
}
2352
2365
}
2353
2366
@@ -2417,8 +2430,12 @@ namespace ts {
2417
2430
bindPropertyAssignment ( node . expression , node , /*isPrototypeProperty*/ false ) ;
2418
2431
}
2419
2432
2433
+ function getJSInitializerSymbolFromName ( name : EntityNameExpression , lookupContainer ?: Node ) : Symbol {
2434
+ return getJSInitializerSymbol ( lookupSymbolForPropertyAccess ( name , lookupContainer ) ) ;
2435
+ }
2436
+
2420
2437
function bindPropertyAssignment ( name : EntityNameExpression , propertyAccess : PropertyAccessEntityNameExpression , isPrototypeProperty : boolean ) {
2421
- let symbol = getJSInitializerSymbol ( lookupSymbolForPropertyAccess ( name ) ) ;
2438
+ let symbol = getJSInitializerSymbolFromName ( name ) ;
2422
2439
let isToplevelNamespaceableInitializer : boolean ;
2423
2440
if ( isBinaryExpression ( propertyAccess . parent ) ) {
2424
2441
const isPrototypeAssignment = isPropertyAccessExpression ( propertyAccess . parent . left ) && propertyAccess . parent . left . name . escapedText === "prototype" ;
@@ -2458,9 +2475,9 @@ namespace ts {
2458
2475
declareSymbol ( symbolTable , symbol , propertyAccess , symbolFlags , symbolExcludes ) ;
2459
2476
}
2460
2477
2461
- function lookupSymbolForPropertyAccess ( node : EntityNameExpression ) : Symbol | undefined {
2478
+ function lookupSymbolForPropertyAccess ( node : EntityNameExpression , lookupContainer : Node = container ) : Symbol | undefined {
2462
2479
if ( isIdentifier ( node ) ) {
2463
- return lookupSymbolForNameWorker ( container , node . escapedText ) ;
2480
+ return lookupSymbolForNameWorker ( lookupContainer , node . escapedText ) ;
2464
2481
}
2465
2482
else {
2466
2483
const symbol = getJSInitializerSymbol ( lookupSymbolForPropertyAccess ( node . expression ) ) ;
0 commit comments