@@ -37,6 +37,7 @@ const (
37
37
ContainerFlagsHasLocals ContainerFlags = 1 << 5
38
38
ContainerFlagsIsInterface ContainerFlags = 1 << 6
39
39
ContainerFlagsIsObjectLiteralOrClassExpressionMethodOrAccessor ContainerFlags = 1 << 7
40
+ ContainerFlagsIsThisContainer ContainerFlags = 1 << 8
40
41
)
41
42
42
43
type Binder struct {
@@ -49,7 +50,7 @@ type Binder struct {
49
50
50
51
parent * ast.Node
51
52
container * ast.Node
52
- thisParentContainer * ast.Node
53
+ thisContainer * ast.Node
53
54
blockScopeContainer * ast.Node
54
55
lastContainer * ast.Node
55
56
currentFlow * ast.FlowNode
@@ -625,7 +626,7 @@ func (b *Binder) bind(node *ast.Node) bool {
625
626
case ast .KindBinaryExpression :
626
627
switch ast .GetAssignmentDeclarationKind (node .AsBinaryExpression ()) {
627
628
case ast .JSDeclarationKindProperty :
628
- b .bindFunctionPropertyAssignment (node )
629
+ b .bindExpandoPropertyAssignment (node )
629
630
case ast .JSDeclarationKindThisProperty :
630
631
b .bindThisPropertyAssignment (node )
631
632
}
@@ -1014,74 +1015,104 @@ func addLateBoundAssignmentDeclarationToSymbol(node *ast.Node, symbol *ast.Symbo
1014
1015
symbol .AssignmentDeclarationMembers .Add (node )
1015
1016
}
1016
1017
1017
- func (b * Binder ) bindFunctionPropertyAssignment (node * ast.Node ) {
1018
+ func (b * Binder ) bindExpandoPropertyAssignment (node * ast.Node ) {
1018
1019
expr := node .AsBinaryExpression ()
1019
- parentName := expr .Left .Expression (). Text ()
1020
- symbol := b .lookupName ( parentName , b .blockScopeContainer )
1020
+ parent := expr .Left .Expression ()
1021
+ symbol := b .lookupEntity ( parent , b .blockScopeContainer )
1021
1022
if symbol == nil {
1022
- symbol = b .lookupName ( parentName , b .container )
1023
+ symbol = b .lookupEntity ( parent , b .container )
1023
1024
}
1024
- if symbol != nil && symbol .ValueDeclaration != nil {
1025
- // For an assignment 'fn.xxx = ...', where 'fn' is a previously declared function or a previously
1026
- // declared const variable initialized with a function expression or arrow function, we add expando
1027
- // property declarations to the function's symbol.
1028
- var funcSymbol * ast.Symbol
1029
- switch {
1030
- case ast .IsFunctionDeclaration (symbol .ValueDeclaration ):
1031
- funcSymbol = symbol
1032
- case ast .IsVariableDeclaration (symbol .ValueDeclaration ) && symbol .ValueDeclaration .Parent .Flags & ast .NodeFlagsConst != 0 :
1033
- initializer := symbol .ValueDeclaration .Initializer ()
1034
- if initializer != nil && ast .IsFunctionExpressionOrArrowFunction (initializer ) {
1035
- funcSymbol = initializer .Symbol ()
1036
- }
1025
+ if symbol = getInitializerSymbol (symbol ); symbol != nil {
1026
+ // Fix up parent pointers since we're going to use these nodes before we bind into them
1027
+ setParent (expr .Left , node )
1028
+ setParent (expr .Right , node )
1029
+ if ast .HasDynamicName (node ) {
1030
+ b .bindAnonymousDeclaration (node , ast .SymbolFlagsProperty | ast .SymbolFlagsAssignment , ast .InternalSymbolNameComputed )
1031
+ addLateBoundAssignmentDeclarationToSymbol (node , symbol )
1032
+ } else {
1033
+ b .declareSymbol (ast .GetExports (symbol ), symbol , node , ast .SymbolFlagsProperty | ast .SymbolFlagsAssignment , ast .SymbolFlagsPropertyExcludes )
1037
1034
}
1038
- if funcSymbol != nil {
1039
- // Fix up parent pointers since we're going to use these nodes before we bind into them
1040
- setParent (expr .Left , node )
1041
- setParent (expr .Right , node )
1042
- if ast .HasDynamicName (node ) {
1043
- b .bindAnonymousDeclaration (node , ast .SymbolFlagsProperty | ast .SymbolFlagsAssignment , ast .InternalSymbolNameComputed )
1044
- addLateBoundAssignmentDeclarationToSymbol (node , funcSymbol )
1045
- } else {
1046
- b .declareSymbol (ast .GetExports (funcSymbol ), funcSymbol , node , ast .SymbolFlagsProperty | ast .SymbolFlagsAssignment , ast .SymbolFlagsPropertyExcludes )
1047
- }
1035
+ }
1036
+ }
1037
+
1038
+ func getInitializerSymbol (symbol * ast.Symbol ) * ast.Symbol {
1039
+ if symbol == nil || symbol .ValueDeclaration == nil {
1040
+ return nil
1041
+ }
1042
+ declaration := symbol .ValueDeclaration
1043
+ // For an assignment 'fn.xxx = ...', where 'fn' is a previously declared function or a previously
1044
+ // declared const variable initialized with a function expression or arrow function, we add expando
1045
+ // property declarations to the function's symbol.
1046
+ // This also applies to class expressions and empty object literals.
1047
+ switch {
1048
+ case ast .IsFunctionDeclaration (declaration ) || ast .IsInJSFile (declaration ) && ast .IsClassDeclaration (declaration ):
1049
+ return symbol
1050
+ case ast .IsVariableDeclaration (declaration ) &&
1051
+ (declaration .Parent .Flags & ast .NodeFlagsConst != 0 || ast .IsInJSFile (declaration )):
1052
+ initializer := declaration .Initializer ()
1053
+ if isExpandoInitializer (initializer ) {
1054
+ return initializer .Symbol ()
1055
+ }
1056
+ case ast .IsBinaryExpression (declaration ) && ast .IsInJSFile (declaration ):
1057
+ initializer := declaration .AsBinaryExpression ().Right
1058
+ if isExpandoInitializer (initializer ) {
1059
+ return initializer .Symbol ()
1048
1060
}
1049
1061
}
1062
+ return nil
1063
+ }
1064
+
1065
+ func isExpandoInitializer (initializer * ast.Node ) bool {
1066
+ if initializer == nil {
1067
+ return false
1068
+ }
1069
+ if ast .IsFunctionExpressionOrArrowFunction (initializer ) {
1070
+ return true
1071
+ } else if ast .IsInJSFile (initializer ) {
1072
+ return ast .IsClassExpression (initializer ) || (ast .IsObjectLiteralExpression (initializer ) && len (initializer .AsObjectLiteralExpression ().Properties .Nodes ) == 0 )
1073
+ }
1074
+ return false
1050
1075
}
1051
1076
1052
1077
func (b * Binder ) bindThisPropertyAssignment (node * ast.Node ) {
1053
1078
if ! ast .IsInJSFile (node ) {
1054
1079
return
1055
1080
}
1056
1081
bin := node .AsBinaryExpression ()
1057
- if ast .IsPropertyAccessExpression (bin .Left ) && ast .IsPrivateIdentifier (bin .Left .AsPropertyAccessExpression ().Name ()) {
1082
+ if ast .IsPropertyAccessExpression (bin .Left ) && ast .IsPrivateIdentifier (bin .Left .AsPropertyAccessExpression ().Name ()) ||
1083
+ b .thisContainer == nil {
1058
1084
return
1059
1085
}
1060
- thisContainer := ast .GetThisContainer (node /*includeArrowFunctions*/ , false /*includeClassComputedPropertyName*/ , false )
1061
- switch thisContainer .Kind {
1086
+ if classSymbol , symbolTable := b .getThisClassAndSymbolTable (); symbolTable != nil {
1087
+ if ast .HasDynamicName (node ) {
1088
+ b .declareSymbolEx (symbolTable , classSymbol , node , ast .SymbolFlagsProperty , ast .SymbolFlagsNone , true /*isReplaceableByMethod*/ , true /*isComputedName*/ )
1089
+ addLateBoundAssignmentDeclarationToSymbol (node , classSymbol )
1090
+ } else {
1091
+ b .declareSymbolEx (symbolTable , classSymbol , node , ast .SymbolFlagsProperty | ast .SymbolFlagsAssignment , ast .SymbolFlagsNone , true /*isReplaceableByMethod*/ , false /*isComputedName*/ )
1092
+ }
1093
+ } else if b .thisContainer .Kind != ast .KindFunctionDeclaration && b .thisContainer .Kind != ast .KindFunctionExpression {
1094
+ // !!! constructor functions
1095
+ panic ("Unhandled case in bindThisPropertyAssignment: " + b .thisContainer .Kind .String ())
1096
+ }
1097
+ }
1098
+
1099
+ func (b * Binder ) getThisClassAndSymbolTable () (classSymbol * ast.Symbol , symbolTable ast.SymbolTable ) {
1100
+ if b .thisContainer == nil {
1101
+ return nil , nil
1102
+ }
1103
+ switch b .thisContainer .Kind {
1062
1104
case ast .KindFunctionDeclaration , ast .KindFunctionExpression :
1063
1105
// !!! constructor functions
1064
1106
case ast .KindConstructor , ast .KindPropertyDeclaration , ast .KindMethodDeclaration , ast .KindGetAccessor , ast .KindSetAccessor , ast .KindClassStaticBlockDeclaration :
1065
1107
// this.property assignment in class member -- bind to the containing class
1066
- containingClass := thisContainer .Parent
1067
- classSymbol := containingClass .Symbol ()
1068
- var symbolTable ast.SymbolTable
1069
- if ast .IsStatic (thisContainer ) {
1070
- symbolTable = ast .GetExports (containingClass .Symbol ())
1071
- } else {
1072
- symbolTable = ast .GetMembers (containingClass .Symbol ())
1073
- }
1074
- if ast .HasDynamicName (node ) {
1075
- b .declareSymbolEx (symbolTable , containingClass .Symbol (), node , ast .SymbolFlagsProperty , ast .SymbolFlagsNone , true /*isReplaceableByMethod*/ , true /*isComputedName*/ )
1076
- addLateBoundAssignmentDeclarationToSymbol (node , classSymbol )
1108
+ classSymbol = b .thisContainer .Parent .Symbol ()
1109
+ if ast .IsStatic (b .thisContainer ) {
1110
+ symbolTable = ast .GetExports (classSymbol )
1077
1111
} else {
1078
- b . declareSymbolEx ( symbolTable , containingClass . Symbol (), node , ast .SymbolFlagsProperty | ast . SymbolFlagsAssignment , ast . SymbolFlagsNone , true /*isReplaceableByMethod*/ , false /*isComputedName*/ )
1112
+ symbolTable = ast .GetMembers ( classSymbol )
1079
1113
}
1080
- case ast .KindSourceFile , ast .KindModuleDeclaration :
1081
- // top-level this.property as assignment to globals is no longer supported
1082
- default :
1083
- panic ("Unhandled case in bindThisPropertyAssignment: " + thisContainer .Kind .String ())
1084
1114
}
1115
+ return classSymbol , symbolTable
1085
1116
}
1086
1117
1087
1118
func (b * Binder ) bindEnumDeclaration (node * ast.Node ) {
@@ -1213,16 +1244,35 @@ func (b *Binder) bindTypeParameter(node *ast.Node) {
1213
1244
}
1214
1245
}
1215
1246
1247
+ func (b * Binder ) lookupEntity (node * ast.Node , container * ast.Node ) * ast.Symbol {
1248
+ if ast .IsIdentifier (node ) {
1249
+ return b .lookupName (node .AsIdentifier ().Text , container )
1250
+ }
1251
+ if ast .IsPropertyAccessExpression (node ) && node .AsPropertyAccessExpression ().Expression .Kind == ast .KindThisKeyword ||
1252
+ ast .IsElementAccessExpression (node ) && node .AsElementAccessExpression ().Expression .Kind == ast .KindThisKeyword {
1253
+ if _ , symbolTable := b .getThisClassAndSymbolTable (); symbolTable != nil {
1254
+ if name := ast .GetElementOrPropertyAccessName (node ); name != nil {
1255
+ return symbolTable [name .Text ()]
1256
+ }
1257
+ }
1258
+ return nil
1259
+ }
1260
+ if symbol := getInitializerSymbol (b .lookupEntity (node .Expression (), container )); symbol != nil && symbol .Exports != nil {
1261
+ if name := ast .GetElementOrPropertyAccessName (node ); name != nil {
1262
+ return symbol .Exports [name .Text ()]
1263
+ }
1264
+ }
1265
+ return nil
1266
+ }
1267
+
1216
1268
func (b * Binder ) lookupName (name string , container * ast.Node ) * ast.Symbol {
1217
- localsContainer := container .LocalsContainerData ()
1218
- if localsContainer != nil {
1219
- local := localsContainer .Locals [name ]
1220
- if local != nil {
1269
+ if localsContainer := container .LocalsContainerData (); localsContainer != nil {
1270
+ if local := localsContainer .Locals [name ]; local != nil {
1221
1271
return core .OrElse (local .ExportSymbol , local )
1222
1272
}
1223
1273
}
1224
- declaration := container . DeclarationData ()
1225
- if declaration != nil && declaration .Symbol != nil {
1274
+
1275
+ if declaration := container . DeclarationData (); declaration != nil && declaration .Symbol != nil {
1226
1276
return declaration .Symbol .Exports [name ]
1227
1277
}
1228
1278
return nil
@@ -1434,7 +1484,7 @@ func (b *Binder) bindContainer(node *ast.Node, containerFlags ContainerFlags) {
1434
1484
// and block-container. Then after we pop out of processing the children, we restore
1435
1485
// these saved values.
1436
1486
saveContainer := b .container
1437
- saveThisParentContainer := b .thisParentContainer
1487
+ saveThisContainer := b .thisContainer
1438
1488
savedBlockScopeContainer := b .blockScopeContainer
1439
1489
// Depending on what kind of node this is, we may have to adjust the current container
1440
1490
// and block-container. If the current node is a container, then it is automatically
@@ -1454,9 +1504,6 @@ func (b *Binder) bindContainer(node *ast.Node, containerFlags ContainerFlags) {
1454
1504
// for it. We must clear this so we don't accidentally move any stale data forward from
1455
1505
// a previous compilation.
1456
1506
if containerFlags & ContainerFlagsIsContainer != 0 {
1457
- if node .Kind != ast .KindArrowFunction {
1458
- b .thisParentContainer = b .container
1459
- }
1460
1507
b .container = node
1461
1508
b .blockScopeContainer = node
1462
1509
if containerFlags & ContainerFlagsHasLocals != 0 {
@@ -1468,6 +1515,9 @@ func (b *Binder) bindContainer(node *ast.Node, containerFlags ContainerFlags) {
1468
1515
b .blockScopeContainer = node
1469
1516
b .addToContainerChain (node )
1470
1517
}
1518
+ if containerFlags & ContainerFlagsIsThisContainer != 0 {
1519
+ b .thisContainer = node
1520
+ }
1471
1521
if containerFlags & ContainerFlagsIsControlFlowContainer != 0 {
1472
1522
saveCurrentFlow := b .currentFlow
1473
1523
saveBreakTarget := b .currentBreakTarget
@@ -1548,7 +1598,7 @@ func (b *Binder) bindContainer(node *ast.Node, containerFlags ContainerFlags) {
1548
1598
b .bindChildren (node )
1549
1599
}
1550
1600
b .container = saveContainer
1551
- b .thisParentContainer = saveThisParentContainer
1601
+ b .thisContainer = saveThisContainer
1552
1602
b .blockScopeContainer = savedBlockScopeContainer
1553
1603
}
1554
1604
@@ -2574,19 +2624,24 @@ func GetContainerFlags(node *ast.Node) ContainerFlags {
2574
2624
return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals
2575
2625
case ast .KindGetAccessor , ast .KindSetAccessor , ast .KindMethodDeclaration :
2576
2626
if ast .IsObjectLiteralOrClassExpressionMethodOrAccessor (node ) {
2577
- return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsIsObjectLiteralOrClassExpressionMethodOrAccessor
2627
+ return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsIsObjectLiteralOrClassExpressionMethodOrAccessor | ContainerFlagsIsThisContainer
2578
2628
}
2579
2629
fallthrough
2580
- case ast .KindConstructor , ast .KindFunctionDeclaration , ast .KindMethodSignature , ast .KindCallSignature , ast .KindJSDocSignature ,
2581
- ast .KindFunctionType , ast .KindConstructSignature , ast .KindConstructorType , ast .KindClassStaticBlockDeclaration :
2630
+ case ast .KindConstructor , ast .KindClassStaticBlockDeclaration :
2631
+ return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsIsThisContainer
2632
+ case ast .KindMethodSignature , ast .KindCallSignature , ast .KindJSDocSignature , ast .KindFunctionType , ast .KindConstructSignature , ast .KindConstructorType :
2582
2633
return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike
2583
- case ast .KindFunctionExpression , ast .KindArrowFunction :
2634
+ case ast .KindFunctionDeclaration :
2635
+ return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsIsThisContainer
2636
+ case ast .KindFunctionExpression :
2637
+ return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsIsFunctionExpression | ContainerFlagsIsThisContainer
2638
+ case ast .KindArrowFunction :
2584
2639
return ContainerFlagsIsContainer | ContainerFlagsIsControlFlowContainer | ContainerFlagsHasLocals | ContainerFlagsIsFunctionLike | ContainerFlagsIsFunctionExpression
2585
2640
case ast .KindModuleBlock :
2586
2641
return ContainerFlagsIsControlFlowContainer
2587
2642
case ast .KindPropertyDeclaration :
2588
2643
if node .AsPropertyDeclaration ().Initializer != nil {
2589
- return ContainerFlagsIsControlFlowContainer
2644
+ return ContainerFlagsIsControlFlowContainer | ContainerFlagsIsThisContainer
2590
2645
} else {
2591
2646
return ContainerFlagsNone
2592
2647
}
0 commit comments