Skip to content

Commit cf3e0c2

Browse files
authored
fix(1374): support declaration emit for expando functions (#1399)
1 parent 7dd4ae5 commit cf3e0c2

File tree

87 files changed

+2462
-537
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+2462
-537
lines changed

internal/ast/utilities.go

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,7 +1340,7 @@ func IsBindableStaticElementAccessExpression(node *Node, excludeThisKeyword bool
13401340
return IsLiteralLikeElementAccess(node) &&
13411341
((!excludeThisKeyword && node.Expression().Kind == KindThisKeyword) ||
13421342
IsEntityNameExpression(node.Expression()) ||
1343-
IsBindableStaticAccessExpression(node.Expression() /*excludeThisKeyword*/, true))
1343+
IsBindableStaticAccessExpression(node.Expression(), true /*excludeThisKeyword*/))
13441344
}
13451345

13461346
func IsLiteralLikeElementAccess(node *Node) bool {
@@ -2822,10 +2822,6 @@ func IsModuleExportsAccessExpression(node *Node) bool {
28222822
return false
28232823
}
28242824

2825-
func isLiteralLikeElementAccess(node *Node) bool {
2826-
return node.Kind == KindElementAccessExpression && IsStringOrNumericLiteralLike(node.AsElementAccessExpression().ArgumentExpression)
2827-
}
2828-
28292825
func IsCheckJSEnabledForFile(sourceFile *SourceFile, compilerOptions *core.CompilerOptions) bool {
28302826
if sourceFile.CheckJsDirective != nil {
28312827
return sourceFile.CheckJsDirective.Enabled
@@ -3866,6 +3862,31 @@ func IsImportOrImportEqualsDeclaration(node *Node) bool {
38663862
return IsImportDeclaration(node) || IsImportEqualsDeclaration(node)
38673863
}
38683864

3865+
func IsKeyword(token Kind) bool {
3866+
return KindFirstKeyword <= token && token <= KindLastKeyword
3867+
}
3868+
3869+
func IsNonContextualKeyword(token Kind) bool {
3870+
return IsKeyword(token) && !IsContextualKeyword(token)
3871+
}
3872+
3873+
func HasModifier(node *Node, flags ModifierFlags) bool {
3874+
return node.ModifierFlags()&flags != 0
3875+
}
3876+
3877+
func IsExpandoInitializer(initializer *Node) bool {
3878+
if initializer == nil {
3879+
return false
3880+
}
3881+
if IsFunctionExpressionOrArrowFunction(initializer) {
3882+
return true
3883+
}
3884+
if IsInJSFile(initializer) {
3885+
return IsClassExpression(initializer) || (IsObjectLiteralExpression(initializer) && len(initializer.AsObjectLiteralExpression().Properties.Nodes) == 0)
3886+
}
3887+
return false
3888+
}
3889+
38693890
func GetContainingFunction(node *Node) *Node {
38703891
return FindAncestor(node.Parent, IsFunctionLike)
38713892
}

internal/binder/binder.go

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,30 +1018,18 @@ func getInitializerSymbol(symbol *ast.Symbol) *ast.Symbol {
10181018
case ast.IsVariableDeclaration(declaration) &&
10191019
(declaration.Parent.Flags&ast.NodeFlagsConst != 0 || ast.IsInJSFile(declaration)):
10201020
initializer := declaration.Initializer()
1021-
if isExpandoInitializer(initializer) {
1021+
if ast.IsExpandoInitializer(initializer) {
10221022
return initializer.Symbol()
10231023
}
10241024
case ast.IsBinaryExpression(declaration) && ast.IsInJSFile(declaration):
10251025
initializer := declaration.AsBinaryExpression().Right
1026-
if isExpandoInitializer(initializer) {
1026+
if ast.IsExpandoInitializer(initializer) {
10271027
return initializer.Symbol()
10281028
}
10291029
}
10301030
return nil
10311031
}
10321032

1033-
func isExpandoInitializer(initializer *ast.Node) bool {
1034-
if initializer == nil {
1035-
return false
1036-
}
1037-
if ast.IsFunctionExpressionOrArrowFunction(initializer) {
1038-
return true
1039-
} else if ast.IsInJSFile(initializer) {
1040-
return ast.IsClassExpression(initializer) || (ast.IsObjectLiteralExpression(initializer) && len(initializer.AsObjectLiteralExpression().Properties.Nodes) == 0)
1041-
}
1042-
return false
1043-
}
1044-
10451033
func (b *Binder) bindThisPropertyAssignment(node *ast.Node) {
10461034
if !ast.IsInJSFile(node) {
10471035
return

internal/binder/referenceresolver.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ type ReferenceResolver interface {
1111
GetReferencedImportDeclaration(node *ast.IdentifierNode) *ast.Declaration
1212
GetReferencedValueDeclaration(node *ast.IdentifierNode) *ast.Declaration
1313
GetReferencedValueDeclarations(node *ast.IdentifierNode) []*ast.Declaration
14+
GetElementAccessExpressionName(expression *ast.ElementAccessExpression) string
1415
}
1516

1617
type ReferenceResolverHooks struct {
@@ -21,6 +22,7 @@ type ReferenceResolverHooks struct {
2122
GetSymbolOfDeclaration func(*ast.Declaration) *ast.Symbol
2223
GetTypeOnlyAliasDeclaration func(symbol *ast.Symbol, include ast.SymbolFlags) *ast.Declaration
2324
GetExportSymbolOfValueSymbolIfExported func(*ast.Symbol) *ast.Symbol
25+
GetElementAccessExpressionName func(*ast.ElementAccessExpression) (string, bool)
2426
}
2527

2628
var _ ReferenceResolver = &referenceResolver{}
@@ -236,3 +238,14 @@ func (r *referenceResolver) GetReferencedValueDeclarations(node *ast.IdentifierN
236238
}
237239
return declarations
238240
}
241+
242+
func (r *referenceResolver) GetElementAccessExpressionName(expression *ast.ElementAccessExpression) string {
243+
if expression != nil {
244+
if r.hooks.GetElementAccessExpressionName != nil {
245+
if name, ok := r.hooks.GetElementAccessExpressionName(expression); ok {
246+
return name
247+
}
248+
}
249+
}
250+
return ""
251+
}

internal/checker/checker.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4234,7 +4234,7 @@ func (c *Checker) checkBaseTypeAccessibility(t *Type, node *ast.Node) {
42344234
signatures := c.getSignaturesOfType(t, SignatureKindConstruct)
42354235
if len(signatures) != 0 {
42364236
declaration := signatures[0].declaration
4237-
if declaration != nil && HasModifier(declaration, ast.ModifierFlagsPrivate) {
4237+
if declaration != nil && ast.HasModifier(declaration, ast.ModifierFlagsPrivate) {
42384238
typeClassDeclaration := ast.GetClassLikeDeclarationOfSymbol(t.symbol)
42394239
if !c.isNodeWithinClass(node, typeClassDeclaration) {
42404240
c.error(node, diagnostics.Cannot_extend_a_class_0_Class_constructor_is_marked_as_private, c.getFullyQualifiedName(t.symbol, nil))
@@ -6489,7 +6489,7 @@ func (c *Checker) checkAliasSymbol(node *ast.Node) {
64896489
name := node.PropertyNameOrName().Text()
64906490
c.addTypeOnlyDeclarationRelatedInfo(c.error(node, message, name), core.IfElse(isType, nil, typeOnlyAlias), name)
64916491
}
6492-
if isType && node.Kind == ast.KindImportEqualsDeclaration && HasModifier(node, ast.ModifierFlagsExport) {
6492+
if isType && node.Kind == ast.KindImportEqualsDeclaration && ast.HasModifier(node, ast.ModifierFlagsExport) {
64936493
c.error(node, diagnostics.Cannot_use_export_import_on_a_type_or_type_only_namespace_when_0_is_enabled, c.getIsolatedModulesLikeFlagName())
64946494
}
64956495
case ast.KindExportSpecifier:
@@ -6777,7 +6777,7 @@ func (c *Checker) checkUnusedClassMembers(node *ast.Node) {
67776777
break // Already would have reported an error on the getter.
67786778
}
67796779
symbol := c.getSymbolOfDeclaration(member)
6780-
if !c.isReferenced(symbol) && (HasModifier(member, ast.ModifierFlagsPrivate) || member.Name() != nil && ast.IsPrivateIdentifier(member.Name())) && member.Flags&ast.NodeFlagsAmbient == 0 {
6780+
if !c.isReferenced(symbol) && (ast.HasModifier(member, ast.ModifierFlagsPrivate) || member.Name() != nil && ast.IsPrivateIdentifier(member.Name())) && member.Flags&ast.NodeFlagsAmbient == 0 {
67816781
c.reportUnused(member, UnusedKindLocal, NewDiagnosticForNode(member.Name(), diagnostics.X_0_is_declared_but_its_value_is_never_read, c.symbolToString(symbol)))
67826782
}
67836783
case ast.KindConstructor:
@@ -8337,7 +8337,7 @@ func (c *Checker) resolveNewExpression(node *ast.Node, candidatesOutArray *[]*Si
83378337
}
83388338
if expressionType.symbol != nil {
83398339
valueDecl := ast.GetClassLikeDeclarationOfSymbol(expressionType.symbol)
8340-
if valueDecl != nil && HasModifier(valueDecl, ast.ModifierFlagsAbstract) {
8340+
if valueDecl != nil && ast.HasModifier(valueDecl, ast.ModifierFlagsAbstract) {
83418341
c.error(node, diagnostics.Cannot_create_an_instance_of_an_abstract_class)
83428342
return c.resolveErrorCall(node)
83438343
}
@@ -18912,7 +18912,7 @@ func (c *Checker) getIndexInfosOfIndexSymbol(indexSymbol *ast.Symbol, siblingSym
1891218912
}
1891318913
forEachType(c.getTypeFromTypeNode(typeNode), func(keyType *Type) {
1891418914
if c.isValidIndexKeyType(keyType) && findIndexInfo(indexInfos, keyType) == nil {
18915-
indexInfo := c.newIndexInfo(keyType, valueType, HasModifier(declaration, ast.ModifierFlagsReadonly), declaration, nil)
18915+
indexInfo := c.newIndexInfo(keyType, valueType, ast.HasModifier(declaration, ast.ModifierFlagsReadonly), declaration, nil)
1891618916
indexInfos = append(indexInfos, indexInfo)
1891718917
}
1891818918
})
@@ -26823,7 +26823,7 @@ func (c *Checker) markPropertyAsReferenced(prop *ast.Symbol, nodeForCheckWriteOn
2682326823
if prop.Flags&ast.SymbolFlagsClassMember == 0 || prop.ValueDeclaration == nil {
2682426824
return
2682526825
}
26826-
hasPrivateModifier := HasModifier(prop.ValueDeclaration, ast.ModifierFlagsPrivate)
26826+
hasPrivateModifier := ast.HasModifier(prop.ValueDeclaration, ast.ModifierFlagsPrivate)
2682726827
hasPrivateIdentifier := prop.ValueDeclaration.Name() != nil && ast.IsPrivateIdentifier(prop.ValueDeclaration.Name())
2682826828
if !hasPrivateModifier && !hasPrivateIdentifier {
2682926829
return

internal/checker/emitresolver.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,7 @@ func (r *emitResolver) getReferenceResolver() binder.ReferenceResolver {
825825
GetSymbolOfDeclaration: r.checker.getSymbolOfDeclaration,
826826
GetTypeOnlyAliasDeclaration: r.checker.getTypeOnlyAliasDeclarationEx,
827827
GetExportSymbolOfValueSymbolIfExported: r.checker.getExportSymbolOfValueSymbolIfExported,
828+
GetElementAccessExpressionName: r.checker.tryGetElementAccessExpressionName,
828829
})
829830
}
830831
return r.referenceResolver
@@ -879,6 +880,17 @@ func (r *emitResolver) GetReferencedValueDeclarations(node *ast.IdentifierNode)
879880
return r.getReferenceResolver().GetReferencedValueDeclarations(node)
880881
}
881882

883+
func (r *emitResolver) GetElementAccessExpressionName(expression *ast.ElementAccessExpression) string {
884+
if !ast.IsParseTreeNode(expression.AsNode()) {
885+
return ""
886+
}
887+
888+
r.checkerMu.Lock()
889+
defer r.checkerMu.Unlock()
890+
891+
return r.getReferenceResolver().GetElementAccessExpressionName(expression)
892+
}
893+
882894
// TODO: the emit resolver being responsible for some amount of node construction is a very leaky abstraction,
883895
// and requires giving it access to a lot of context it's otherwise not required to have, which also further complicates the API
884896
// and likely reduces performance. There's probably some refactoring that could be done here to simplify this.

internal/checker/utilities.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,8 @@ func getSelectedModifierFlags(node *ast.Node, flags ast.ModifierFlags) ast.Modif
7676
return node.ModifierFlags() & flags
7777
}
7878

79-
func HasModifier(node *ast.Node, flags ast.ModifierFlags) bool {
80-
return node.ModifierFlags()&flags != 0
81-
}
82-
8379
func hasReadonlyModifier(node *ast.Node) bool {
84-
return HasModifier(node, ast.ModifierFlagsReadonly)
80+
return ast.HasModifier(node, ast.ModifierFlagsReadonly)
8581
}
8682

8783
func isStaticPrivateIdentifierProperty(s *ast.Symbol) bool {
@@ -405,7 +401,7 @@ func declarationBelongsToPrivateAmbientMember(declaration *ast.Node) bool {
405401
}
406402

407403
func isPrivateWithinAmbient(node *ast.Node) bool {
408-
return (HasModifier(node, ast.ModifierFlagsPrivate) || ast.IsPrivateIdentifierClassElementDeclaration(node)) && node.Flags&ast.NodeFlagsAmbient != 0
404+
return (ast.HasModifier(node, ast.ModifierFlagsPrivate) || ast.IsPrivateIdentifierClassElementDeclaration(node)) && node.Flags&ast.NodeFlagsAmbient != 0
409405
}
410406

411407
func isTypeAssertion(node *ast.Node) bool {

internal/ls/findallreferences.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ func getSymbolScope(symbol *ast.Symbol) *ast.Node {
349349
// If this is private property or method, the scope is the containing class
350350
if symbol.Flags&(ast.SymbolFlagsProperty|ast.SymbolFlagsMethod) != 0 {
351351
privateDeclaration := core.Find(declarations, func(d *ast.Node) bool {
352-
return checker.HasModifier(d, ast.ModifierFlagsPrivate) || ast.IsPrivateIdentifierClassElementDeclaration(d)
352+
return ast.HasModifier(d, ast.ModifierFlagsPrivate) || ast.IsPrivateIdentifierClassElementDeclaration(d)
353353
})
354354
if privateDeclaration != nil {
355355
return ast.FindAncestorKind(privateDeclaration, ast.KindClassDeclaration)

internal/parser/parser.go

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ func (p *Parser) lookAhead(callback func(p *Parser) bool) bool {
296296

297297
func (p *Parser) nextToken() ast.Kind {
298298
// if the keyword had an escape
299-
if isKeyword(p.token) && (p.scanner.HasUnicodeEscape() || p.scanner.HasExtendedUnicodeEscape()) {
299+
if ast.IsKeyword(p.token) && (p.scanner.HasUnicodeEscape() || p.scanner.HasExtendedUnicodeEscape()) {
300300
// issue a parse error for the escape
301301
p.parseErrorAtCurrentToken(diagnostics.Keywords_cannot_contain_escape_characters)
302302
}
@@ -644,7 +644,7 @@ func (p *Parser) parsingContextErrors(context ParsingContext) {
644644
case PCHeritageClauseElement:
645645
p.parseErrorAtCurrentToken(diagnostics.Expression_expected)
646646
case PCVariableDeclarations:
647-
if isKeyword(p.token) {
647+
if ast.IsKeyword(p.token) {
648648
p.parseErrorAtCurrentToken(diagnostics.X_0_is_not_allowed_as_a_variable_declaration_name, scanner.TokenToString(p.token))
649649
} else {
650650
p.parseErrorAtCurrentToken(diagnostics.Variable_declaration_expected)
@@ -662,7 +662,7 @@ func (p *Parser) parsingContextErrors(context ParsingContext) {
662662
case PCJSDocParameters:
663663
p.parseErrorAtCurrentToken(diagnostics.Parameter_declaration_expected)
664664
case PCParameters:
665-
if isKeyword(p.token) {
665+
if ast.IsKeyword(p.token) {
666666
p.parseErrorAtCurrentToken(diagnostics.X_0_is_not_allowed_as_a_parameter_name, scanner.TokenToString(p.token))
667667
} else {
668668
p.parseErrorAtCurrentToken(diagnostics.Parameter_declaration_expected)
@@ -2352,7 +2352,7 @@ func (p *Parser) parseModuleExportName(disallowKeywords bool) (node *ast.Node, n
23522352
if p.token == ast.KindStringLiteral {
23532353
return p.parseLiteralExpression(false /*intern*/), nameOk
23542354
}
2355-
if disallowKeywords && isKeyword(p.token) && !p.isIdentifier() {
2355+
if disallowKeywords && ast.IsKeyword(p.token) && !p.isIdentifier() {
23562356
nameOk = false
23572357
}
23582358
return p.parseIdentifierName(), nameOk
@@ -5835,7 +5835,7 @@ func (p *Parser) scanClassMemberStart() bool {
58355835
// If we were able to get any potential identifier...
58365836
if idToken != ast.KindUnknown {
58375837
// If we have a non-keyword identifier, or if we have an accessor, then it's safe to parse.
5838-
if !isKeyword(idToken) || idToken == ast.KindSetKeyword || idToken == ast.KindGetKeyword {
5838+
if !ast.IsKeyword(idToken) || idToken == ast.KindSetKeyword || idToken == ast.KindGetKeyword {
58395839
return true
58405840
}
58415841
// If it *is* a keyword, but not an accessor, check a little farther along
@@ -6235,10 +6235,6 @@ func (p *Parser) skipRangeTrivia(textRange core.TextRange) core.TextRange {
62356235
return core.NewTextRange(scanner.SkipTrivia(p.sourceText, textRange.Pos()), textRange.End())
62366236
}
62376237

6238-
func isKeyword(token ast.Kind) bool {
6239-
return ast.KindFirstKeyword <= token && token <= ast.KindLastKeyword
6240-
}
6241-
62426238
func isReservedWord(token ast.Kind) bool {
62436239
return ast.KindFirstReservedWord <= token && token <= ast.KindLastReservedWord
62446240
}

0 commit comments

Comments
 (0)