From 13ab4f82c84d31b1d43a8c7b5240abc1b5c82c97 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 22 Jul 2026 21:18:54 -0700 Subject: [PATCH 1/3] Use serializable symbol name keys --- internal/api/session.go | 2 +- internal/ast/symbol.go | 86 +++-- internal/ast/symbol_test.go | 29 ++ internal/ast/utilities.go | 10 +- internal/binder/binder.go | 61 ++-- internal/binder/nameresolver.go | 10 +- internal/checker/checker.go | 315 +++++++++--------- internal/checker/exports.go | 8 +- internal/checker/flow.go | 38 ++- internal/checker/inference.go | 5 +- internal/checker/jsx.go | 36 +- internal/checker/nodebuilder_hover.go | 24 +- internal/checker/nodebuilderimpl.go | 28 +- internal/checker/nodebuilderscopes.go | 19 +- internal/checker/relater.go | 45 +-- internal/checker/services.go | 33 +- internal/checker/symbolaccessibility.go | 2 +- internal/checker/types.go | 12 +- internal/checker/utilities.go | 29 +- internal/ls/autoimport/export.go | 10 +- internal/ls/autoimport/extract.go | 26 +- internal/ls/autoimport/fix.go | 4 +- internal/ls/autoimport/import_adder.go | 2 +- internal/ls/autoimport/util.go | 2 +- ..._fixclassincorrectlyimplementsinterface.go | 2 +- .../codeactions_fixmissingtypeannotation.go | 7 +- internal/ls/codeactions_importfixes.go | 2 +- internal/ls/codeactions_missingmemberfixer.go | 4 +- internal/ls/completions.go | 26 +- internal/ls/findallreferences.go | 9 +- internal/ls/hover.go | 4 +- internal/ls/importTracker.go | 11 +- internal/ls/inlay_hints.go | 2 +- internal/ls/lsutil/utilities.go | 2 +- internal/ls/signaturehelp.go | 5 +- internal/ls/string_completions.go | 12 +- internal/printer/namegenerator.go | 2 +- internal/testutil/fsbaselineutil/differ.go | 8 +- .../tsbaseline/type_symbol_baseline.go | 2 +- internal/tracing/tracing.go | 4 +- .../transformers/declarations/transform.go | 2 +- .../submodule/compiler/enumWithBigint.types | 2 +- .../compiler/enumWithBigint.types.diff | 10 - .../conformance/privateNameEnum.types | 2 +- .../conformance/privateNameEnum.types.diff | 9 - .../internal-symbolname-in-tsbuildInfo.js | 14 +- 46 files changed, 505 insertions(+), 472 deletions(-) create mode 100644 internal/ast/symbol_test.go delete mode 100644 testdata/baselines/reference/submodule/compiler/enumWithBigint.types.diff delete mode 100644 testdata/baselines/reference/submodule/conformance/privateNameEnum.types.diff diff --git a/internal/api/session.go b/internal/api/session.go index 8eb9aa9738f..0456c214454 100644 --- a/internal/api/session.go +++ b/internal/api/session.go @@ -143,7 +143,7 @@ func (sd *snapshotData) newSymbolResponse(symbol *ast.Symbol, canonicalProject P resp := &SymbolResponse{ Id: id, Project: project, - Name: ast.EscapeSymbolName(symbol.Name), + Name: symbol.Name.EscapedText(), Flags: uint32(symbol.Flags), CheckFlags: uint32(symbol.CheckFlags), } diff --git a/internal/ast/symbol.go b/internal/ast/symbol.go index f4ffd566ea9..1023ceecbec 100644 --- a/internal/ast/symbol.go +++ b/internal/ast/symbol.go @@ -1,7 +1,6 @@ package ast import ( - "strings" "sync/atomic" ) @@ -10,7 +9,7 @@ import ( type Symbol struct { Flags SymbolFlags CheckFlags CheckFlags // Non-zero only in transient symbols created by Checker - Name string + Name SymbolNameKey Declarations []*Node ValueDeclaration *Node Members SymbolTable @@ -42,62 +41,61 @@ func (s *Symbol) CombinedLocalAndExportSymbolFlags() SymbolFlags { // SymbolTable -type SymbolTable map[string]*Symbol +type SymbolNameKey string -const InternalSymbolNamePrefix = "\xFE" // Invalid UTF8 sequence, will never occur as IdentifierName +type SymbolTable map[SymbolNameKey]*Symbol + +func (name SymbolNameKey) EscapedText() string { + return string(name) +} + +func InternalSymbolName(suffix string) SymbolNameKey { + return SymbolNameKey(InternalSymbolNamePrefix + suffix) +} + +const InternalSymbolNamePrefix = "__" const ( - InternalSymbolNameCall = InternalSymbolNamePrefix + "call" // Call signatures - InternalSymbolNameConstructor = InternalSymbolNamePrefix + "constructor" // Constructor implementations - InternalSymbolNameNew = InternalSymbolNamePrefix + "new" // Constructor signatures - InternalSymbolNameIndex = InternalSymbolNamePrefix + "index" // Index signatures - InternalSymbolNameExportStar = InternalSymbolNamePrefix + "export" // Module export * declarations - InternalSymbolNameGlobal = InternalSymbolNamePrefix + "global" // Global self-reference - InternalSymbolNameMissing = InternalSymbolNamePrefix + "missing" // Indicates missing symbol - InternalSymbolNameType = InternalSymbolNamePrefix + "type" // Anonymous type literal symbol - InternalSymbolNameObject = InternalSymbolNamePrefix + "object" // Anonymous object literal declaration - InternalSymbolNameJSXAttributes = InternalSymbolNamePrefix + "jsxAttributes" // Anonymous JSX attributes object literal declaration - InternalSymbolNameClass = InternalSymbolNamePrefix + "class" // Unnamed class expression - InternalSymbolNameFunction = InternalSymbolNamePrefix + "function" // Unnamed function expression - InternalSymbolNameComputed = InternalSymbolNamePrefix + "computed" // Computed property name declaration with dynamic name - InternalSymbolNameAssignmentDeclaration = InternalSymbolNamePrefix + "assignment" // Assignment declarations - InternalSymbolNameInstantiationExpression = InternalSymbolNamePrefix + "instantiationExpression" // Instantiation expressions - InternalSymbolNameImportAttributes = InternalSymbolNamePrefix + "importAttributes" - InternalSymbolNameExportEquals = "export=" // Export assignment symbol - InternalSymbolNameDefault = "default" // Default export symbol (technically not wholly internal, but included here for usability) - InternalSymbolNameThis = "this" - InternalSymbolNameModuleExports = "module.exports" + InternalSymbolNameCall SymbolNameKey = InternalSymbolNamePrefix + "call" // Call signatures + InternalSymbolNameConstructor SymbolNameKey = InternalSymbolNamePrefix + "constructor" // Constructor implementations + InternalSymbolNameNew SymbolNameKey = InternalSymbolNamePrefix + "new" // Constructor signatures + InternalSymbolNameIndex SymbolNameKey = InternalSymbolNamePrefix + "index" // Index signatures + InternalSymbolNameExportStar SymbolNameKey = InternalSymbolNamePrefix + "export" // Module export * declarations + InternalSymbolNameGlobal SymbolNameKey = InternalSymbolNamePrefix + "global" // Global self-reference + InternalSymbolNameMissing SymbolNameKey = InternalSymbolNamePrefix + "missing" // Indicates missing symbol + InternalSymbolNameType SymbolNameKey = InternalSymbolNamePrefix + "type" // Anonymous type literal symbol + InternalSymbolNameObject SymbolNameKey = InternalSymbolNamePrefix + "object" // Anonymous object literal declaration + InternalSymbolNameJSXAttributes SymbolNameKey = InternalSymbolNamePrefix + "jsxAttributes" // Anonymous JSX attributes object literal declaration + InternalSymbolNameClass SymbolNameKey = InternalSymbolNamePrefix + "class" // Unnamed class expression + InternalSymbolNameFunction SymbolNameKey = InternalSymbolNamePrefix + "function" // Unnamed function expression + InternalSymbolNameComputed SymbolNameKey = InternalSymbolNamePrefix + "computed" // Computed property name declaration with dynamic name + InternalSymbolNameAssignmentDeclaration SymbolNameKey = InternalSymbolNamePrefix + "assignment" // Assignment declarations + InternalSymbolNameInstantiationExpression SymbolNameKey = InternalSymbolNamePrefix + "instantiationExpression" // Instantiation expressions + InternalSymbolNameImportAttributes SymbolNameKey = InternalSymbolNamePrefix + "importAttributes" + InternalSymbolNameExportEquals SymbolNameKey = "export=" // Export assignment symbol + InternalSymbolNameDefault SymbolNameKey = "default" // Default export symbol (technically not wholly internal, but included here for usability) + InternalSymbolNameThis SymbolNameKey = "this" + InternalSymbolNameModuleExports SymbolNameKey = "module.exports" ) func SymbolName(symbol *Symbol) string { if symbol.ValueDeclaration != nil && IsPrivateIdentifierClassElementDeclaration(symbol.ValueDeclaration) { return symbol.ValueDeclaration.Name().Text() } - return symbol.Name + return UnescapeLeadingUnderscores(symbol.Name) } -// EscapeAllInternalSymbolNames replaces internal symbol name markers ("\xFE") with "__". -func EscapeAllInternalSymbolNames(name string) string { - return strings.ReplaceAll(name, InternalSymbolNamePrefix, "__") -} - -func EscapeInternalSymbolName(name string) string { - if rest, ok := strings.CutPrefix(name, InternalSymbolNamePrefix); ok { - return "__" + rest +func EscapeLeadingUnderscores(identifier string) SymbolNameKey { + if len(identifier) >= 2 && identifier[0] == '_' && identifier[1] == '_' { + return SymbolNameKey("_" + identifier) } - return name + return SymbolNameKey(identifier) } -// EscapeSymbolName converts a binder symbol name into its escaped "__String" -// form. Internal names (prefixed with the "\xFE" sentinel) become "__"-prefixed, -// and user names that already begin with "__" gain an extra leading underscore -// so they can be distinguished from internal names. -func EscapeSymbolName(name string) string { - if rest, ok := strings.CutPrefix(name, InternalSymbolNamePrefix); ok { - return "__" + rest - } - if len(name) >= 2 && name[0] == '_' && name[1] == '_' { - return "_" + name +func UnescapeLeadingUnderscores(identifier SymbolNameKey) string { + name := string(identifier) + if len(name) >= 3 && name[0] == '_' && name[1] == '_' && name[2] == '_' { + return name[1:] } return name } diff --git a/internal/ast/symbol_test.go b/internal/ast/symbol_test.go new file mode 100644 index 00000000000..58f85605dfc --- /dev/null +++ b/internal/ast/symbol_test.go @@ -0,0 +1,29 @@ +package ast_test + +import ( + "testing" + "unicode/utf8" + + "github.com/microsoft/typescript-go/internal/ast" + "github.com/microsoft/typescript-go/internal/json" + "gotest.tools/v3/assert" +) + +func TestSymbolNameEncoding(t *testing.T) { + t.Parallel() + + internalName := ast.InternalSymbolNameCall + userName := ast.EscapeLeadingUnderscores("__call") + + assert.Assert(t, utf8.ValidString(string(internalName))) + assert.Assert(t, internalName != userName) + assert.Equal(t, internalName.EscapedText(), "__call") + assert.Equal(t, userName.EscapedText(), "___call") + assert.Equal(t, ast.UnescapeLeadingUnderscores(userName), "__call") + + encoded, err := json.Marshal([]ast.SymbolNameKey{internalName, userName}) + assert.NilError(t, err) + var decoded []string + assert.NilError(t, json.Unmarshal(encoded, &decoded)) + assert.DeepEqual(t, decoded, []string{string(internalName), string(userName)}) +} diff --git a/internal/ast/utilities.go b/internal/ast/utilities.go index 551ab4018ca..28cad0f2e45 100644 --- a/internal/ast/utilities.go +++ b/internal/ast/utilities.go @@ -2537,7 +2537,7 @@ func GetNamespaceDeclarationNode(node *Node) *Node { } func ModuleExportNameIsDefault(node *Node) bool { - return node.Text() == InternalSymbolNameDefault + return EscapeLeadingUnderscores(node.Text()) == InternalSymbolNameDefault } func IsDefaultImport(node *Node /*ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration*/) bool { @@ -3157,22 +3157,22 @@ func isShorthandPropertyNameUseSite(useSite *Node) bool { return IsIdentifier(useSite) && IsShorthandPropertyAssignment(useSite.Parent) && useSite.Parent.AsShorthandPropertyAssignment().Name() == useSite } -func GetPropertyNameForPropertyNameNode(name *Node) string { +func GetPropertyNameForPropertyNameNode(name *Node) SymbolNameKey { switch name.Kind { case KindIdentifier, KindPrivateIdentifier, KindStringLiteral, KindNoSubstitutionTemplateLiteral, KindNumericLiteral, KindBigIntLiteral, KindJsxNamespacedName: - return name.Text() + return EscapeLeadingUnderscores(name.Text()) case KindComputedPropertyName: nameExpression := name.Expression() if IsStringOrNumericLiteralLike(nameExpression) { - return nameExpression.Text() + return EscapeLeadingUnderscores(nameExpression.Text()) } if IsSignedNumericLiteral(nameExpression) { text := nameExpression.AsPrefixUnaryExpression().Operand.Text() if nameExpression.AsPrefixUnaryExpression().Operator == KindMinusToken { text = "-" + text } - return text + return EscapeLeadingUnderscores(text) } return InternalSymbolNameMissing } diff --git a/internal/binder/binder.go b/internal/binder/binder.go index c029ef3b23b..a5cf60e4dad 100644 --- a/internal/binder/binder.go +++ b/internal/binder/binder.go @@ -131,7 +131,7 @@ func bindSourceFile(file *ast.SourceFile) { }) } -func (b *Binder) newSymbol(flags ast.SymbolFlags, name string) *ast.Symbol { +func (b *Binder) newSymbol(flags ast.SymbolFlags, name ast.SymbolNameKey) *ast.Symbol { b.symbolCount++ result := b.symbolArena.New() result.Flags = flags @@ -155,7 +155,7 @@ func (b *Binder) declareSymbolEx(symbolTable ast.SymbolTable, parent *ast.Symbol debug.Assert(isComputedName || !ast.HasDynamicName(node)) isDefaultExport := ast.HasSyntacticModifier(node, ast.ModifierFlagsDefault) || ast.IsExportSpecifier(node) && ast.ModuleExportNameIsDefault(node.AsExportSpecifier().Name()) // The exported symbol for an export default function/class node is always named "default" - var name string + var name ast.SymbolNameKey switch { case isComputedName: name = ast.InternalSymbolNameComputed @@ -193,7 +193,7 @@ func (b *Binder) declareSymbolEx(symbolTable ast.SymbolTable, parent *ast.Symbol // just add this node into the declarations list of the symbol. symbol = symbolTable[name] if includes&ast.SymbolFlagsClassifiable != 0 { - b.classifiableNames.Add(name) + b.classifiableNames.Add(string(name)) } if symbol == nil { symbol = b.newSymbol(ast.SymbolFlagsNone, name) @@ -303,9 +303,12 @@ func (b *Binder) declareSymbolEx(symbolTable ast.SymbolTable, parent *ast.Symbol // Should not be called on a declaration with a computed property name, // unless it is a well known Symbol. -func (b *Binder) getDeclarationName(node *ast.Node) string { +func (b *Binder) getDeclarationName(node *ast.Node) ast.SymbolNameKey { if ast.IsExportAssignment(node) { - return core.IfElse(node.AsExportAssignment().IsExportEquals, ast.InternalSymbolNameExportEquals, ast.InternalSymbolNameDefault) + if node.AsExportAssignment().IsExportEquals { + return ast.InternalSymbolNameExportEquals + } + return ast.InternalSymbolNameDefault } name := ast.GetNameOfDeclaration(node) if name != nil { @@ -314,7 +317,7 @@ func (b *Binder) getDeclarationName(node *ast.Node) string { if ast.IsGlobalScopeAugmentation(node) { return ast.InternalSymbolNameGlobal } - return "\"" + moduleName + "\"" + return ast.EscapeLeadingUnderscores("\"" + moduleName + "\"") } if ast.IsPrivateIdentifier(name) { // containingClass exists because private names only allowed inside classes @@ -326,17 +329,17 @@ func (b *Binder) getDeclarationName(node *ast.Node) string { return GetSymbolNameForPrivateIdentifier(containingClass.Symbol(), name.Text()) } if ast.IsPropertyNameLiteral(name) || ast.IsJsxNamespacedName(name) { - return name.Text() + return ast.EscapeLeadingUnderscores(name.Text()) } if ast.IsComputedPropertyName(name) { nameExpression := name.Expression() // treat computed property names where expression is string/numeric literal as just string/numeric literal if ast.IsStringOrNumericLiteralLike(nameExpression) { - return nameExpression.Text() + return ast.EscapeLeadingUnderscores(nameExpression.Text()) } if ast.IsSignedNumericLiteral(nameExpression) { unaryExpression := nameExpression.AsPrefixUnaryExpression() - return scanner.TokenToString(unaryExpression.Operator) + unaryExpression.Operand.Text() + return ast.EscapeLeadingUnderscores(scanner.TokenToString(unaryExpression.Operator) + unaryExpression.Operand.Text()) } panic("Only computed properties with literal names have declaration names") } @@ -366,13 +369,13 @@ func (b *Binder) getDisplayName(node *ast.Node) string { } name := b.getDeclarationName(node) if name != ast.InternalSymbolNameMissing { - return name + return string(name) } return "(Missing)" } -func GetSymbolNameForPrivateIdentifier(containingClassSymbol *ast.Symbol, description string) string { - return ast.InternalSymbolNamePrefix + "#" + strconv.Itoa(int(ast.GetSymbolId(containingClassSymbol))) + "@" + description +func GetSymbolNameForPrivateIdentifier(containingClassSymbol *ast.Symbol, description string) ast.SymbolNameKey { + return ast.InternalSymbolName("#" + strconv.Itoa(int(ast.GetSymbolId(containingClassSymbol))) + "@" + description) } func (b *Binder) declareModuleMember(node *ast.Node, symbolFlags ast.SymbolFlags, symbolExcludes ast.SymbolFlags) *ast.Symbol { @@ -770,7 +773,7 @@ func (b *Binder) bindSourceFileIfExternalModule() { } func (b *Binder) bindSourceFileAsExternalModule() { - b.bindAnonymousDeclaration(b.file.AsNode(), ast.SymbolFlagsValueModule, "\""+tspath.RemoveFileExtension(b.file.FileName())+"\"") + b.bindAnonymousDeclaration(b.file.AsNode(), ast.SymbolFlagsValueModule, ast.EscapeLeadingUnderscores("\""+tspath.RemoveFileExtension(b.file.FileName())+"\"")) } func (b *Binder) bindModuleDeclaration(node *ast.Node) { @@ -916,7 +919,7 @@ func (b *Binder) bindFunctionExpression(node *ast.Node) { bindingName := ast.InternalSymbolNameFunction if ast.IsFunctionExpression(node) && node.AsFunctionExpression().Name() != nil { b.checkStrictModeFunctionName(node) - bindingName = node.AsFunctionExpression().Name().Text() + bindingName = ast.EscapeLeadingUnderscores(node.AsFunctionExpression().Name().Text()) } b.bindAnonymousDeclaration(node, ast.SymbolFlagsFunction, bindingName) } @@ -950,8 +953,8 @@ func (b *Binder) bindClassLikeDeclaration(node *ast.Node) { case ast.KindClassExpression: nameText := ast.InternalSymbolNameClass if name != nil { - nameText = name.Text() - b.classifiableNames.Add(nameText) + nameText = ast.EscapeLeadingUnderscores(name.Text()) + b.classifiableNames.Add(string(nameText)) } b.bindAnonymousDeclaration(node, ast.SymbolFlagsClass, nameText) } @@ -965,7 +968,7 @@ func (b *Binder) bindClassLikeDeclaration(node *ast.Node) { // Note: we check for this here because this class may be merging into a module. The // module might have an exported variable called 'prototype'. We can't allow that as // that would clash with the built-in 'prototype' for the class. - prototypeSymbol := b.newSymbol(ast.SymbolFlagsProperty|ast.SymbolFlagsPrototype, "prototype") + prototypeSymbol := b.newSymbol(ast.SymbolFlagsProperty|ast.SymbolFlagsPrototype, ast.EscapeLeadingUnderscores("prototype")) symbolExport := ast.GetExports(symbol)[prototypeSymbol.Name] if symbolExport != nil { b.errorOnNode(symbolExport.Declarations[0], diagnostics.Duplicate_identifier_0, ast.SymbolName(prototypeSymbol)) @@ -1201,7 +1204,7 @@ func (b *Binder) bindParameter(node *ast.Node) { } if ast.IsBindingPattern(decl.Name()) { index := slices.Index(node.Parent.Parameters(), node) - b.bindAnonymousDeclaration(node, ast.SymbolFlagsFunctionScopedVariable, "__"+strconv.Itoa(index)) + b.bindAnonymousDeclaration(node, ast.SymbolFlagsFunctionScopedVariable, ast.InternalSymbolName(strconv.Itoa(index))) } else { b.declareSymbolAndAddToSymbolTable(node, ast.SymbolFlagsFunctionScopedVariable, ast.SymbolFlagsParameterExcludes) } @@ -1233,7 +1236,7 @@ func (b *Binder) getInferTypeContainer(node *ast.Node) *ast.Node { return nil } -func (b *Binder) bindAnonymousDeclaration(node *ast.Node, symbolFlags ast.SymbolFlags, name string) { +func (b *Binder) bindAnonymousDeclaration(node *ast.Node, symbolFlags ast.SymbolFlags, name ast.SymbolNameKey) { symbol := b.newSymbol(symbolFlags, name) if symbolFlags&(ast.SymbolFlagsEnumMember|ast.SymbolFlagsClassMember) != 0 { symbol.Parent = b.container.Symbol() @@ -1276,27 +1279,28 @@ func (b *Binder) lookupEntity(node *ast.Node, container *ast.Node) *ast.Symbol { if node.Expression().Kind == ast.KindThisKeyword { if _, symbolTable := b.getThisClassAndSymbolTable(); symbolTable != nil { if name := ast.GetElementOrPropertyAccessName(node); name != nil { - return symbolTable[name.Text()] + return symbolTable[ast.EscapeLeadingUnderscores(name.Text())] } } return nil } if symbol := getInitializerSymbol(b.lookupEntity(node.Expression(), container)); symbol != nil && symbol.Exports != nil { if name := ast.GetElementOrPropertyAccessName(node); name != nil { - return symbol.Exports[name.Text()] + return symbol.Exports[ast.EscapeLeadingUnderscores(name.Text())] } } return nil } func (b *Binder) lookupName(name string, container *ast.Node) *ast.Symbol { + symbolName := ast.EscapeLeadingUnderscores(name) if localsContainer := container.LocalsContainerData(); localsContainer != nil { - if local := localsContainer.Locals[name]; local != nil { + if local := localsContainer.Locals[symbolName]; local != nil { return core.OrElse(local.ExportSymbol, local) } } if declaration := container.DeclarationData(); declaration != nil && declaration.Symbol != nil { - return declaration.Symbol.Exports[name] + return declaration.Symbol.Exports[symbolName] } return nil } @@ -1625,20 +1629,21 @@ func (b *Binder) bindContainer(node *ast.Node, containerFlags ContainerFlags) { } func (b *Binder) declareCommonJSVariable(name string) { + symbolName := ast.EscapeLeadingUnderscores(name) locals := ast.GetLocals(b.file.AsNode()) - if locals[name] == nil { - symbol := b.newSymbol(ast.SymbolFlagsFunctionScopedVariable|ast.SymbolFlagsModuleExports, name) + if locals[symbolName] == nil { + symbol := b.newSymbol(ast.SymbolFlagsFunctionScopedVariable|ast.SymbolFlagsModuleExports, symbolName) symbol.Declarations = b.newSingleDeclaration(b.file.AsNode()) symbol.ValueDeclaration = symbol.Declarations[0] if name == "module" { - exportsProperty := b.newSymbol(ast.SymbolFlagsModuleExports|ast.SymbolFlagsProperty, "exports") + exportsProperty := b.newSymbol(ast.SymbolFlagsModuleExports|ast.SymbolFlagsProperty, ast.EscapeLeadingUnderscores("exports")) exportsProperty.Declarations = symbol.Declarations exportsProperty.ValueDeclaration = symbol.ValueDeclaration exportsProperty.Parent = symbol symbol.Members = make(ast.SymbolTable, 1) - symbol.Members["exports"] = exportsProperty + symbol.Members[ast.EscapeLeadingUnderscores("exports")] = exportsProperty } - locals[name] = symbol + locals[symbolName] = symbol } } diff --git a/internal/binder/nameresolver.go b/internal/binder/nameresolver.go index 2ab0ab5af83..abee2f96300 100644 --- a/internal/binder/nameresolver.go +++ b/internal/binder/nameresolver.go @@ -113,7 +113,7 @@ loop: result = moduleExports[ast.InternalSymbolNameDefault] if result != nil { localSymbol := GetLocalSymbolForExportDefault(result) - if localSymbol != nil && result.Flags&meaning != 0 && localSymbol.Name == name { + if localSymbol != nil && result.Flags&meaning != 0 && localSymbol.Name == ast.EscapeLeadingUnderscores(name) { break loop } result = nil @@ -129,12 +129,12 @@ loop: // 2. We check === SymbolFlags.Alias in order to check that the symbol is *purely* // an alias. If we used &, we'd be throwing out symbols that have non alias aspects, // which is not the desired behavior. - moduleExport := moduleExports[name] + moduleExport := moduleExports[ast.EscapeLeadingUnderscores(name)] if moduleExport != nil && moduleExport.Flags == ast.SymbolFlagsAlias && (ast.GetDeclarationOfKind(moduleExport, ast.KindExportSpecifier) != nil || ast.GetDeclarationOfKind(moduleExport, ast.KindNamespaceExport) != nil) { break } } - if name != ast.InternalSymbolNameDefault { + if ast.EscapeLeadingUnderscores(name) != ast.InternalSymbolNameDefault { if result = r.lookup(moduleExports, name, meaning&ast.SymbolFlagsModuleMember); result != nil { if ast.IsSourceFile(location) && location.AsSourceFile().CommonJSModuleIndicator != nil && result.Flags&ast.SymbolFlagsType == 0 { result = nil @@ -153,7 +153,7 @@ loop: if nameNotFoundMessage != nil && r.CompilerOptions.GetIsolatedModules() && location.Flags&ast.NodeFlagsAmbient == 0 && ast.GetSourceFileOfNode(location) != ast.GetSourceFileOfNode(result.ValueDeclaration) { isolatedModulesLikeFlagName := core.IfElse(r.CompilerOptions.VerbatimModuleSyntax == core.TSTrue, "verbatimModuleSyntax", "isolatedModules") r.error(originalLocation, diagnostics.Cannot_access_0_from_another_file_without_qualification_when_1_is_enabled_Use_2_instead, - name, isolatedModulesLikeFlagName, enumSymbol.Name+"."+name) + name, isolatedModulesLikeFlagName, ast.UnescapeLeadingUnderscores(enumSymbol.Name)+"."+name) } break loop } @@ -421,7 +421,7 @@ func (r *NameResolver) lookup(symbols ast.SymbolTable, name string, meaning ast. } // Default implementation does not support following aliases or merged symbols if meaning != 0 { - symbol := symbols[name] + symbol := symbols[ast.EscapeLeadingUnderscores(name)] if symbol != nil { if symbol.Flags&meaning != 0 { return symbol diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 59fae08cee3..9e42dd0afc6 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -534,11 +534,11 @@ type IterationTypesResolver struct { } type WideningContext struct { - parent *WideningContext // Parent context - propertyName string // Name of property in parent - siblings []*Type // Types of siblings - resolvedProperties []*ast.Symbol // Properties occurring in sibling object literals - childContexts map[string]*WideningContext + parent *WideningContext // Parent context + propertyName ast.SymbolNameKey // Name of property in parent + siblings []*Type // Types of siblings + resolvedProperties []*ast.Symbol // Properties occurring in sibling object literals + childContexts map[ast.SymbolNameKey]*WideningContext widenedTypes map[*Type]*Type } @@ -630,7 +630,7 @@ type Checker struct { subtypeReductionCache map[CacheHashKey][]*Type cachedTypes map[CachedTypeKey]*Type cachedSignatures map[CachedSignatureKey]*Signature - undefinedProperties map[string]*ast.Symbol + undefinedProperties map[ast.SymbolNameKey]*ast.Symbol narrowedTypes map[NarrowedTypeKey]*Type assignmentReducedTypes map[AssignmentReducedKey]*Type discriminatedContextualTypes map[DiscriminatedContextualTypeKey]*Type @@ -942,7 +942,7 @@ func NewChecker(program Program, tracer *Tracer) (*Checker, *sync.Mutex) { c.subtypeReductionCache = make(map[CacheHashKey][]*Type) c.cachedTypes = make(map[CachedTypeKey]*Type) c.cachedSignatures = make(map[CachedSignatureKey]*Signature) - c.undefinedProperties = make(map[string]*ast.Symbol) + c.undefinedProperties = make(map[ast.SymbolNameKey]*ast.Symbol) c.narrowedTypes = make(map[NarrowedTypeKey]*Type) c.assignmentReducedTypes = make(map[AssignmentReducedKey]*Type) c.discriminatedContextualTypes = make(map[DiscriminatedContextualTypeKey]*Type) @@ -1307,7 +1307,7 @@ func (c *Checker) initializeChecker() { for _, symbol := range file.Locals { // We defer merging of global ambient module declarations since they may require other global symbols // and types to be resolved. See https://github.com/microsoft/typescript-go/issues/2953. - if symbol.Flags&ast.SymbolFlagsModule != 0 && ast.IsAmbientModuleSymbolName(symbol.Name) { + if symbol.Flags&ast.SymbolFlagsModule != 0 && ast.IsAmbientModuleSymbolName(ast.UnescapeLeadingUnderscores(symbol.Name)) { ambientModuleSymbols = append(ambientModuleSymbols, symbol) } else { c.mergeGlobalSymbol(symbol) @@ -1428,7 +1428,7 @@ func (c *Checker) mergeModuleAugmentation(moduleName *ast.Node) { }) { merged := c.mergeSymbol(moduleAugmentation.Symbol, mainModule, true /*unidirectional*/) // moduleName will be a StringLiteral since this is not `declare global`. - ast.GetSymbolTable(&c.patternAmbientModuleAugmentations)[moduleName.Text()] = merged + ast.GetSymbolTable(&c.patternAmbientModuleAugmentations)[ast.EscapeLeadingUnderscores(moduleName.Text())] = merged } else { if mainModule.Exports[ast.InternalSymbolNameExportStar] != nil && len(moduleAugmentation.Symbol.Exports) != 0 { // We may need to merge the module augmentation's exports into the target symbols of the resolved exports @@ -1541,7 +1541,7 @@ func (c *Checker) checkAndReportErrorForMissingPrefix(errorLocation *ast.Node, n } // Check to see if a static member exists. constructorType := c.getTypeOfSymbol(classSymbol) - if c.getPropertyOfType(constructorType, name) != nil { + if c.getPropertyOfType(constructorType, ast.EscapeLeadingUnderscores(name)) != nil { c.error(errorLocation, diagnostics.Cannot_find_name_0_Did_you_mean_the_static_member_1_0, name, c.symbolToString(classSymbol)) return true } @@ -1550,7 +1550,7 @@ func (c *Checker) checkAndReportErrorForMissingPrefix(errorLocation *ast.Node, n if location == container && !ast.IsStatic(location) { instanceType := c.getDeclaredTypeOfSymbol(classSymbol).AsInterfaceType().thisType // TODO: GH#18217 - if c.getPropertyOfType(instanceType, name) != nil { + if c.getPropertyOfType(instanceType, ast.EscapeLeadingUnderscores(name)) != nil { c.error(errorLocation, diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0, name) return true } @@ -1607,7 +1607,7 @@ func (c *Checker) checkAndReportErrorForUsingTypeAsNamespace(errorLocation *ast. if ast.IsQualifiedName(parent) { debug.Assert(parent.AsQualifiedName().Left == errorLocation, "Should only be resolving left side of qualified name as a namespace") propName := parent.AsQualifiedName().Right.Text() - propType := c.getPropertyOfType(c.getDeclaredTypeOfSymbol(symbol), propName) + propType := c.getPropertyOfType(c.getDeclaredTypeOfSymbol(symbol), ast.EscapeLeadingUnderscores(propName)) if propType != nil { c.error(parent, diagnostics.Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1, name, propName) return true @@ -1739,7 +1739,7 @@ var primitiveTypeAliasSuggestions = sync.OnceValue(func() map[string]*ast.Symbol } { sym := &ast.Symbol{} sym.Flags = ast.SymbolFlagsTypeAlias | ast.SymbolFlagsTransient - sym.Name = e.primitive + sym.Name = ast.EscapeLeadingUnderscores(e.primitive) result[e.builtin] = sym } return result @@ -1748,7 +1748,7 @@ var primitiveTypeAliasSuggestions = sync.OnceValue(func() map[string]*ast.Symbol func getPrimitiveTypeAliasSuggestions(symbols ast.SymbolTable) iter.Seq[*ast.Symbol] { return func(yield func(*ast.Symbol) bool) { for builtinName, suggestion := range primitiveTypeAliasSuggestions() { - if _, ok := symbols[builtinName]; ok { + if _, ok := symbols[ast.EscapeLeadingUnderscores(builtinName)]; ok { if !yield(suggestion) { return } @@ -1785,7 +1785,7 @@ func (c *Checker) getSuggestionForSymbolNameLookup(symbols ast.SymbolTable, name func (c *Checker) getSpellingSuggestionForName(name string, symbols iter.Seq[*ast.Symbol], meaning ast.SymbolFlags) *ast.Symbol { getCandidateName := func(candidate *ast.Symbol) string { candidateName := ast.SymbolName(candidate) - if len(candidateName) == 0 || candidateName[0] == '"' || candidateName[0] == '\xFE' { + if len(candidateName) == 0 || candidateName[0] == '"' || isReservedMemberName(candidate.Name) { return "" } if candidate.Flags&meaning != 0 { @@ -1803,7 +1803,7 @@ func (c *Checker) getSpellingSuggestionForName(name string, symbols iter.Seq[*as } func (c *Checker) onSuccessfullyResolvedSymbol(errorLocation *ast.Node, result *ast.Symbol, meaning ast.SymbolFlags, lastLocation *ast.Node, associatedDeclarationForContainingInitializerOrBindingName *ast.Node, withinDeferredContext bool) { - name := result.Name + name := ast.UnescapeLeadingUnderscores(result.Name) isInExternalModule := lastLocation != nil && ast.IsSourceFile(lastLocation) && ast.IsExternalOrCommonJSModule(lastLocation.AsSourceFile()) // Only check for block-scoped variable if we have an error location and are looking for the // name with variable meaning @@ -1838,7 +1838,7 @@ func (c *Checker) onSuccessfullyResolvedSymbol(errorLocation *ast.Node, result * // A parameter initializer or binding pattern initializer within a parameter cannot refer to itself if candidate == c.getSymbolOfDeclaration(associatedDeclarationForContainingInitializerOrBindingName) { c.error(errorLocation, diagnostics.Parameter_0_cannot_reference_itself, scanner.DeclarationNameToString(associatedDeclarationForContainingInitializerOrBindingName.Name())) - } else if candidate.ValueDeclaration != nil && candidate.ValueDeclaration.Pos() > associatedDeclarationForContainingInitializerOrBindingName.Pos() && root.Parent.Locals() != nil && c.getSymbol(root.Parent.Locals(), candidate.Name, meaning) == candidate { + } else if candidate.ValueDeclaration != nil && candidate.ValueDeclaration.Pos() > associatedDeclarationForContainingInitializerOrBindingName.Pos() && root.Parent.Locals() != nil && c.getSymbol(root.Parent.Locals(), ast.UnescapeLeadingUnderscores(candidate.Name), meaning) == candidate { c.error(errorLocation, diagnostics.Parameter_0_cannot_reference_identifier_1_declared_after_it, scanner.DeclarationNameToString(associatedDeclarationForContainingInitializerOrBindingName.Name()), scanner.DeclarationNameToString(errorLocation)) } } @@ -2160,7 +2160,7 @@ func (c *Checker) addTypeOnlyDeclarationRelatedInfo(diagnostic *ast.Diagnostic, func (c *Checker) getSymbol(symbols ast.SymbolTable, name string, meaning ast.SymbolFlags) *ast.Symbol { if meaning&ast.SymbolFlagsAll != 0 { - symbol := c.getMergedSymbol(symbols[name]) + symbol := c.getMergedSymbol(symbols[ast.EscapeLeadingUnderscores(name)]) if symbol != nil { if symbol.Flags&meaning != 0 { return symbol @@ -2546,7 +2546,7 @@ func (c *Checker) resolveJSDocMemberName(name *ast.Node) *ast.Symbol { if symbol := c.resolveJSDocMemberName(name.AsQualifiedName().Left); symbol != nil { var t *Type if symbol.Flags&ast.SymbolFlagsValue != 0 { - proto := c.getPropertyOfType(c.getTypeOfSymbol(symbol), "prototype") + proto := c.getPropertyOfType(c.getTypeOfSymbol(symbol), ast.EscapeLeadingUnderscores("prototype")) if proto != nil { t = c.getTypeOfSymbol(proto) } @@ -2554,7 +2554,7 @@ func (c *Checker) resolveJSDocMemberName(name *ast.Node) *ast.Symbol { if t == nil { t = c.getDeclaredTypeOfSymbol(symbol) } - return c.getPropertyOfType(t, name.AsQualifiedName().Right.Text()) + return c.getPropertyOfType(t, ast.EscapeLeadingUnderscores(name.AsQualifiedName().Right.Text())) } } } @@ -2992,7 +2992,7 @@ func (c *Checker) checkTypeReferenceOrImport(node *ast.Node) { symbol := c.getResolvedSymbolOrNil(node) if symbol != nil { if core.Some(symbol.Declarations, func(d *ast.Node) bool { return ast.IsTypeDeclaration(d) && c.IsDeprecatedDeclaration(d) }) { - c.addDeprecatedSuggestion(c.getDeprecatedSuggestionNode(node), symbol.Declarations, symbol.Name) + c.addDeprecatedSuggestion(c.getDeprecatedSuggestionNode(node), symbol.Declarations, ast.UnescapeLeadingUnderscores(symbol.Name)) } } } @@ -3123,21 +3123,21 @@ func (c *Checker) checkTypeLiteral(node *ast.Node) { } func (c *Checker) checkObjectTypeForDuplicateDeclarations(node *ast.Node, checkPrivateNames bool) { - var instanceNames map[string]int - var staticNames map[string]int - var privateNames map[string]int + var instanceNames map[ast.SymbolNameKey]int + var staticNames map[ast.SymbolNameKey]int + var privateNames map[ast.SymbolNameKey]int nodeInAmbientContext := node.Flags&ast.NodeFlagsAmbient != 0 checkPropertyOrAccessor := func(symbol *ast.Symbol, kind int, isStatic bool) { if len(symbol.Declarations) > 1 { - var names map[string]int + var names map[ast.SymbolNameKey]int if isStatic { if staticNames == nil { - staticNames = make(map[string]int) + staticNames = make(map[ast.SymbolNameKey]int) } names = staticNames } else { if instanceNames == nil { - instanceNames = make(map[string]int) + instanceNames = make(map[ast.SymbolNameKey]int) } names = instanceNames } @@ -3181,7 +3181,7 @@ func (c *Checker) checkObjectTypeForDuplicateDeclarations(node *ast.Node, checkP if flags := privateNames[symbol.Name]; flags != 3 { flags |= core.IfElse(ast.IsStatic(member), 2, 1) if privateNames == nil { - privateNames = make(map[string]int) + privateNames = make(map[ast.SymbolNameKey]int) } privateNames[symbol.Name] = flags if flags == 3 { @@ -3193,7 +3193,7 @@ func (c *Checker) checkObjectTypeForDuplicateDeclarations(node *ast.Node, checkP } } -func (c *Checker) reportDuplicateMemberErrors(node *ast.Node, name string, checkStatic bool, isStatic bool, message *diagnostics.Message) { +func (c *Checker) reportDuplicateMemberErrors(node *ast.Node, name ast.SymbolNameKey, checkStatic bool, isStatic bool, message *diagnostics.Message) { for _, member := range node.Members() { if ast.IsConstructorDeclaration(member) { for _, param := range member.Parameters() { @@ -4434,7 +4434,7 @@ func (c *Checker) areTypeParametersIdentical(declarations []*ast.Node, targetPar target := targetParameters[i] // If the type parameter node does not have the same name as the resolved type // parameter at this position, we report an error. - if source.Name().Text() != target.symbol.Name { + if ast.EscapeLeadingUnderscores(source.Name().Text()) != target.symbol.Name { return false } // If the type parameter node does not have an identical constraintNode as the resolved @@ -5016,7 +5016,7 @@ func (c *Checker) checkInheritedPropertiesAreIdentical(t *Type, typeNode *ast.No if len(baseTypes) < 2 { return true } - seen := make(map[string]InheritanceInfo) + seen := make(map[ast.SymbolNameKey]InheritanceInfo) for id, p := range c.resolveDeclaredMembers(t).declaredMembers { if c.isNamedMember(p, id) { seen[p.Name] = InheritanceInfo{prop: p, containingType: t} @@ -5427,7 +5427,7 @@ func (c *Checker) getTypeFromImportAttributes(node *ast.Node) *Type { symbol := c.newSymbol(ast.SymbolFlagsObjectLiteral, ast.InternalSymbolNameImportAttributes) members := make(ast.SymbolTable) for _, attr := range node.AsImportAttributes().Attributes.Nodes { - member := c.newSymbol(ast.SymbolFlagsProperty, attr.Name().Text()) + member := c.newSymbol(ast.SymbolFlagsProperty, ast.EscapeLeadingUnderscores(attr.Name().Text())) c.valueSymbolLinks.Get(member).resolvedType = c.getRegularTypeOfLiteralType(c.checkExpression(attr.AsImportAttribute().Value)) members[member.Name] = member } @@ -6523,7 +6523,7 @@ func (c *Checker) getIterationTypesOfIteratorSlow(t *Type, r *IterationTypesReso } func (c *Checker) getIterationTypesOfMethod(t *Type, resolver *IterationTypesResolver, methodName string, errorNode *ast.Node, diagnosticOutput *[]*ast.Diagnostic) IterationTypes { - method := c.getPropertyOfType(t, methodName) + method := c.getPropertyOfType(t, ast.EscapeLeadingUnderscores(methodName)) // Ignore 'return' or 'throw' if they are missing. if method == nil && methodName != "next" { return IterationTypes{} @@ -6561,8 +6561,9 @@ func (c *Checker) getIterationTypesOfMethod(t *Type, resolver *IterationTypesRes if len(methodSignatures) == 1 && methodType.symbol != nil { globalGeneratorType := resolver.getGlobalGeneratorType() globalIteratorType := resolver.getGlobalIteratorType() - isGeneratorMethod := globalGeneratorType.symbol != nil && globalGeneratorType.symbol.Members[methodName] == methodType.symbol - isIteratorMethod := !isGeneratorMethod && globalIteratorType.symbol != nil && globalIteratorType.symbol.Members[methodName] == methodType.symbol + methodSymbolName := ast.EscapeLeadingUnderscores(methodName) + isGeneratorMethod := globalGeneratorType.symbol != nil && globalGeneratorType.symbol.Members[methodSymbolName] == methodType.symbol + isIteratorMethod := !isGeneratorMethod && globalIteratorType.symbol != nil && globalIteratorType.symbol.Members[methodSymbolName] == methodType.symbol if isGeneratorMethod || isIteratorMethod { typeParameters := core.IfElse(isGeneratorMethod, globalGeneratorType, globalIteratorType).AsInterfaceType().TypeParameters() mapper := methodType.Mapper() @@ -6700,7 +6701,7 @@ func (c *Checker) getIterationDiagnosticDetails(use IterationUse, inputType *Typ if yieldType != nil { return diagnostics.Type_0_can_only_be_iterated_through_when_using_the_downlevelIteration_flag_or_with_a_target_of_es2015_or_higher, false } - if inputType.symbol != nil && isES2015OrLaterIterable(inputType.symbol.Name) { + if inputType.symbol != nil && isES2015OrLaterIterable(ast.UnescapeLeadingUnderscores(inputType.symbol.Name)) { return diagnostics.Type_0_can_only_be_iterated_through_when_using_the_downlevelIteration_flag_or_with_a_target_of_es2015_or_higher, true } if allowsStrings { @@ -6738,14 +6739,14 @@ func (c *Checker) checkAliasSymbol(node *ast.Node) { if ast.IsExportSpecifier(node) { diag := c.error(errorNode, diagnostics.Types_cannot_appear_in_export_declarations_in_JavaScript_files) if sourceSymbol := ast.GetSourceFileOfNode(node).AsNode().Symbol(); sourceSymbol != nil { - if alreadyExportedSymbol := sourceSymbol.Exports[node.PropertyNameOrName().Text()]; alreadyExportedSymbol == target { + if alreadyExportedSymbol := sourceSymbol.Exports[ast.EscapeLeadingUnderscores(node.PropertyNameOrName().Text())]; alreadyExportedSymbol == target { if exportingDeclaration := core.Find(alreadyExportedSymbol.Declarations, ast.IsJSTypeAliasDeclaration); exportingDeclaration != nil { diag.AddRelatedInfo(NewDiagnosticForNode(exportingDeclaration, diagnostics.X_0_is_automatically_exported_here, alreadyExportedSymbol.Name)) } } } } else { - identifierText := symbol.Name + identifierText := ast.UnescapeLeadingUnderscores(symbol.Name) if ast.IsIdentifier(errorNode) { identifierText = errorNode.Text() } @@ -6840,7 +6841,7 @@ func (c *Checker) checkAliasSymbol(node *ast.Node) { if ast.IsImportSpecifier(node) { targetSymbol := c.resolveAliasWithDeprecationCheck(symbol, node) if c.isDeprecatedSymbol(targetSymbol) && targetSymbol.Declarations != nil { - c.addDeprecatedSuggestion(node, targetSymbol.Declarations, targetSymbol.Name) + c.addDeprecatedSuggestion(node, targetSymbol.Declarations, ast.UnescapeLeadingUnderscores(targetSymbol.Name)) } } } @@ -7668,10 +7669,10 @@ func (c *Checker) getUniqueTypeParameters(context *InferenceContext, typeParamet var newTypeParameters []*Type result := make([]*Type, 0, len(typeParameters)) for _, tp := range typeParameters { - name := tp.symbol.Name + name := ast.UnescapeLeadingUnderscores(tp.symbol.Name) if hasTypeParameterByName(context.inferredTypeParameters, name) || hasTypeParameterByName(result, name) { newName := getUniqueTypeParameterName(core.Concatenate(context.inferredTypeParameters, result), name) - symbol := c.newSymbol(ast.SymbolFlagsTypeParameter, newName) + symbol := c.newSymbol(ast.SymbolFlagsTypeParameter, ast.EscapeLeadingUnderscores(newName)) newTypeParameter := c.newTypeParameter(symbol) newTypeParameter.AsTypeParameter().target = tp oldTypeParameters = append(oldTypeParameters, tp) @@ -7692,7 +7693,7 @@ func (c *Checker) getUniqueTypeParameters(context *InferenceContext, typeParamet func hasTypeParameterByName(typeParameters []*Type, name string) bool { return core.Some(typeParameters, func(tp *Type) bool { - return tp.symbol.Name == name + return tp.symbol.Name == ast.EscapeLeadingUnderscores(name) }) } @@ -8227,7 +8228,7 @@ func (c *Checker) checkIndexedAccessIndexType(t *Type, accessNode *ast.Node) *Ty if propertyName != ast.InternalSymbolNameMissing { propertySymbol := c.getConstituentProperty(objectType, propertyName) if propertySymbol != nil && getDeclarationModifierFlagsFromSymbol(propertySymbol)&ast.ModifierFlagsNonPublicAccessibilityModifier != 0 { - c.error(accessNode, diagnostics.Private_or_protected_member_0_cannot_be_accessed_on_a_type_parameter, propertyName) + c.error(accessNode, diagnostics.Private_or_protected_member_0_cannot_be_accessed_on_a_type_parameter, ast.UnescapeLeadingUnderscores(propertyName)) return c.errorType } } @@ -8236,7 +8237,7 @@ func (c *Checker) checkIndexedAccessIndexType(t *Type, accessNode *ast.Node) *Ty return c.errorType } -func (c *Checker) getConstituentProperty(objectType *Type, propertyName string) *ast.Symbol { +func (c *Checker) getConstituentProperty(objectType *Type, propertyName ast.SymbolNameKey) *ast.Symbol { for _, t := range c.getApparentType(objectType).Distributed() { prop := c.getPropertyOfType(t, propertyName) if prop != nil { @@ -11297,14 +11298,14 @@ func (c *Checker) checkPropertyAccessExpressionOrQualifiedName(node *ast.Node, l } return apparentType } - prop = c.getPropertyOfTypeEx(apparentType, right.Text(), isConstEnumObjectType(apparentType) /*skipObjectFunctionPropertyAugment*/, node.Kind == ast.KindQualifiedName /*includeTypeOnlyMembers*/) + prop = c.getPropertyOfTypeEx(apparentType, ast.EscapeLeadingUnderscores(right.Text()), isConstEnumObjectType(apparentType) /*skipObjectFunctionPropertyAugment*/, node.Kind == ast.KindQualifiedName /*includeTypeOnlyMembers*/) } c.markLinkedReferences(node, ReferenceHintProperty, prop, leftType) var propType *Type if prop == nil { var indexInfo *IndexInfo if !ast.IsPrivateIdentifier(right) && (assignmentKind == AssignmentKindNone || !c.isGenericObjectType(leftType) || isThisTypeParameter(leftType)) { - indexInfo = c.getApplicableIndexInfoForName(apparentType, right.Text()) + indexInfo = c.getApplicableIndexInfoForName(apparentType, ast.EscapeLeadingUnderscores(right.Text())) } if indexInfo == nil { isUncheckedJS := c.isUncheckedJSSuggestion(node, leftType.symbol, true /*excludeClasses*/) @@ -11312,7 +11313,7 @@ func (c *Checker) checkPropertyAccessExpressionOrQualifiedName(node *ast.Node, l return c.anyType } if leftType.symbol == c.globalThisSymbol { - globalSymbol := c.globalThisSymbol.Exports[right.Text()] + globalSymbol := c.globalThisSymbol.Exports[ast.EscapeLeadingUnderscores(right.Text())] if globalSymbol != nil && globalSymbol.Flags&ast.SymbolFlagsBlockScoped != 0 { c.error(right, diagnostics.Property_0_does_not_exist_on_type_1, right.Text(), c.TypeToString(leftType)) } else if c.noImplicitAny { @@ -11521,7 +11522,7 @@ func (c *Checker) reportNonexistentProperty(propNode *ast.Node, containingType * var diagnostic *ast.Diagnostic if !ast.IsPrivateIdentifier(propNode) && containingType.flags&TypeFlagsUnion != 0 && containingType.flags&TypeFlagsPrimitive == 0 { for _, subtype := range containingType.Types() { - if c.getPropertyOfType(subtype, propNode.Text()) == nil && c.getApplicableIndexInfoForName(subtype, propNode.Text()) == nil { + if c.getPropertyOfType(subtype, ast.EscapeLeadingUnderscores(propNode.Text())) == nil && c.getApplicableIndexInfoForName(subtype, ast.EscapeLeadingUnderscores(propNode.Text())) == nil { diagnostic = NewDiagnosticChainForNode(diagnostic, propNode, diagnostics.Property_0_does_not_exist_on_type_1, scanner.DeclarationNameToString(propNode), c.TypeToString(subtype)) break } @@ -11533,7 +11534,7 @@ func (c *Checker) reportNonexistentProperty(propNode *ast.Node, containingType * diagnostic = NewDiagnosticChainForNode(diagnostic, propNode, diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_to_access_the_static_member_2_instead, propName, typeName, typeName+"."+propName) } else { promisedType := c.GetPromisedTypeOfPromise(containingType) - if promisedType != nil && c.getPropertyOfType(promisedType, propNode.Text()) != nil { + if promisedType != nil && c.getPropertyOfType(promisedType, ast.EscapeLeadingUnderscores(propNode.Text())) != nil { diagnostic = NewDiagnosticChainForNode(diagnostic, propNode, diagnostics.Property_0_does_not_exist_on_type_1, scanner.DeclarationNameToString(propNode), c.TypeToString(containingType)) diagnostic.AddRelatedInfo(NewDiagnosticForNode(propNode, diagnostics.Did_you_forget_to_use_await)) } else { @@ -11571,7 +11572,7 @@ func (c *Checker) getSuggestedLibForNonExistentProperty(missingProperty string, container := c.getApparentType(containingType).symbol if container != nil { featureMap := getFeatureMap() - if typeFeatures, ok := featureMap[container.Name]; ok { + if typeFeatures, ok := featureMap[ast.UnescapeLeadingUnderscores(container.Name)]; ok { for _, entry := range typeFeatures { if slices.Contains(entry.props, missingProperty) { return entry.lib @@ -11636,7 +11637,7 @@ func hasCommonDomTypeName(t *Type) bool { if t.symbol == nil { return false } - name := t.symbol.Name + name := ast.UnescapeLeadingUnderscores(t.symbol.Name) return name == "EventTarget" || name == "Node" || name == "Element" || strings.HasPrefix(name, "HTML") && strings.HasSuffix(name, "Element") } @@ -12739,7 +12740,7 @@ func (c *Checker) checkAssignmentOperator(left *ast.Node, operator ast.Kind, rig if c.checkReferenceExpression(left, diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access, diagnostics.The_left_hand_side_of_an_assignment_expression_may_not_be_an_optional_property_access) { var headMessage *diagnostics.Message if c.exactOptionalPropertyTypes && ast.IsPropertyAccessExpression(left) && c.maybeTypeOfKind(rightType, TypeFlagsUndefined) { - target := c.getTypeOfPropertyOfType(c.getTypeOfExpression(left.Expression()), left.Name().Text()) + target := c.getTypeOfPropertyOfType(c.getTypeOfExpression(left.Expression()), ast.EscapeLeadingUnderscores(left.Name().Text())) if c.isExactOptionalPropertyMismatch(rightType, target) { headMessage = diagnostics.Type_0_is_not_assignable_to_type_1_with_exactOptionalPropertyTypes_Colon_true_Consider_adding_undefined_to_the_type_of_the_target } @@ -13389,7 +13390,7 @@ func (c *Checker) getSpreadType(left *Type, right *Type, symbol *ast.Symbol, obj return c.getIntersectionType([]*Type{left, right}) } members := make(ast.SymbolTable) - var skippedPrivateMembers collections.Set[string] + var skippedPrivateMembers collections.Set[ast.SymbolNameKey] var indexInfos []*IndexInfo if left == c.emptyObjectType { indexInfos = c.getIndexInfosOfType(right) @@ -14019,7 +14020,7 @@ func (c *Checker) hasParseDiagnostics(sourceFile *ast.SourceFile) bool { return len(sourceFile.Diagnostics()) > 0 } -func (c *Checker) newSymbol(flags ast.SymbolFlags, name string) *ast.Symbol { +func (c *Checker) newSymbol(flags ast.SymbolFlags, name ast.SymbolNameKey) *ast.Symbol { c.SymbolCount++ result := c.symbolArena.New() result.Flags = flags | ast.SymbolFlagsTransient @@ -14027,20 +14028,20 @@ func (c *Checker) newSymbol(flags ast.SymbolFlags, name string) *ast.Symbol { return result } -func (c *Checker) newSymbolEx(flags ast.SymbolFlags, name string, checkFlags ast.CheckFlags) *ast.Symbol { +func (c *Checker) newSymbolEx(flags ast.SymbolFlags, name ast.SymbolNameKey, checkFlags ast.CheckFlags) *ast.Symbol { result := c.newSymbol(flags, name) result.CheckFlags = checkFlags return result } func (c *Checker) newParameter(name string, t *Type) *ast.Symbol { - symbol := c.newSymbol(ast.SymbolFlagsFunctionScopedVariable, name) + symbol := c.newSymbol(ast.SymbolFlagsFunctionScopedVariable, ast.EscapeLeadingUnderscores(name)) c.valueSymbolLinks.Get(symbol).resolvedType = t return symbol } func (c *Checker) newProperty(name string, t *Type) *ast.Symbol { - symbol := c.newSymbol(ast.SymbolFlagsProperty, name) + symbol := c.newSymbol(ast.SymbolFlagsProperty, ast.EscapeLeadingUnderscores(name)) c.valueSymbolLinks.Get(symbol).resolvedType = t return symbol } @@ -14398,7 +14399,7 @@ func (c *Checker) getTargetOfImportEqualsDeclaration(node *ast.Node) *ast.Symbol immediate := c.resolveExternalModuleName(node, moduleReference, false /*ignoreErrors*/) resolved := c.resolveExternalModuleSymbol(immediate, true /*dontResolveAlias*/) if resolved != nil && core.ModuleKindNode20 <= c.moduleKind && c.moduleKind <= core.ModuleKindNodeNext { - moduleExports := c.getExportOfModule(resolved, ast.InternalSymbolNameModuleExports, node, true /*dontResolveAlias*/) + moduleExports := c.getExportOfModule(resolved, ast.UnescapeLeadingUnderscores(ast.InternalSymbolNameModuleExports), node, true /*dontResolveAlias*/) if moduleExports != nil { return moduleExports } @@ -14497,7 +14498,7 @@ func (c *Checker) getTargetOfModuleDefault(moduleSymbol *ast.Symbol, node *ast.N core.ModuleKindNode20 <= c.moduleKind && c.moduleKind <= core.ModuleKindNodeNext && c.getEmitSyntaxForModuleSpecifierExpression(specifier) == core.ModuleKindCommonJS && c.program.GetImpliedNodeFormatForEmit(file.AsSourceFile()) == core.ModuleKindESNext { - exportModuleDotExportsSymbol = c.resolveExportByName(moduleSymbol, ast.InternalSymbolNameModuleExports, node, dontResolveAlias) + exportModuleDotExportsSymbol = c.resolveExportByName(moduleSymbol, ast.UnescapeLeadingUnderscores(ast.InternalSymbolNameModuleExports), node, dontResolveAlias) } if exportModuleDotExportsSymbol != nil { // We have a transpiled default import where the `require` resolves to an ES module with a `module.exports` named @@ -14508,7 +14509,7 @@ func (c *Checker) getTargetOfModuleDefault(moduleSymbol *ast.Symbol, node *ast.N c.markSymbolOfAliasDeclarationIfTypeOnly(node, nil) return exportModuleDotExportsSymbol } else { - exportDefaultSymbol = c.resolveExportByName(moduleSymbol, ast.InternalSymbolNameDefault, node, dontResolveAlias) + exportDefaultSymbol = c.resolveExportByName(moduleSymbol, ast.UnescapeLeadingUnderscores(ast.InternalSymbolNameDefault), node, dontResolveAlias) } if specifier == nil { return exportDefaultSymbol @@ -14568,9 +14569,9 @@ func (c *Checker) resolveExportByName(moduleSymbol *ast.Symbol, name string, sou exportValue := moduleSymbol.Exports[ast.InternalSymbolNameExportEquals] var exportSymbol *ast.Symbol if exportValue != nil { - exportSymbol = c.getPropertyOfTypeEx(c.getTypeOfSymbol(exportValue), name, true /*skipObjectFunctionPropertyAugment*/, false /*includeTypeOnlyMembers*/) + exportSymbol = c.getPropertyOfTypeEx(c.getTypeOfSymbol(exportValue), ast.EscapeLeadingUnderscores(name), true /*skipObjectFunctionPropertyAugment*/, false /*includeTypeOnlyMembers*/) } else { - exportSymbol = moduleSymbol.Exports[name] + exportSymbol = moduleSymbol.Exports[ast.EscapeLeadingUnderscores(name)] } resolved := c.resolveSymbolEx(exportSymbol, dontResolveAlias) c.markSymbolOfAliasDeclarationIfTypeOnly(sourceNode, nil) @@ -14648,7 +14649,7 @@ func (c *Checker) getExternalModuleMember(node *ast.Node, specifier *ast.Node, d var symbolFromVariable *ast.Symbol // First check if module was specified with "export=". If so, get the member from the resolved type if moduleSymbol != nil && moduleSymbol.Exports[ast.InternalSymbolNameExportEquals] != nil { - symbolFromVariable = c.getPropertyOfTypeEx(c.getTypeOfSymbol(targetSymbol), nameText, true /*skipObjectFunctionPropertyAugment*/, false /*includeTypeOnlyMembers*/) + symbolFromVariable = c.getPropertyOfTypeEx(c.getTypeOfSymbol(targetSymbol), ast.EscapeLeadingUnderscores(nameText), true /*skipObjectFunctionPropertyAugment*/, false /*includeTypeOnlyMembers*/) } else { symbolFromVariable = c.getPropertyOfVariable(targetSymbol, nameText) } @@ -14660,7 +14661,7 @@ func (c *Checker) getExternalModuleMember(node *ast.Node, specifier *ast.Node, d exportContainer = moduleSymbol } symbolFromModule := c.getExportOfModule(exportContainer, nameText, specifier, dontResolveAlias) - if symbolFromModule == nil && nameText == ast.InternalSymbolNameDefault { + if symbolFromModule == nil && ast.EscapeLeadingUnderscores(nameText) == ast.InternalSymbolNameDefault { file := core.Find(moduleSymbol.Declarations, ast.IsSourceFile) if c.isOnlyImportableAsDefault(moduleSpecifier, moduleSymbol) || c.canHaveSyntheticDefault(file, moduleSymbol, dontResolveAlias, moduleSpecifier) { symbolFromModule = c.resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) @@ -14676,7 +14677,7 @@ func (c *Checker) getExternalModuleMember(node *ast.Node, specifier *ast.Node, d symbol = c.combineValueAndTypeSymbols(symbolFromVariable, symbolFromModule) } } - if ast.IsImportOrExportSpecifier(specifier) && c.isOnlyImportableAsDefault(moduleSpecifier, moduleSymbol) && nameText != ast.InternalSymbolNameDefault { + if ast.IsImportOrExportSpecifier(specifier) && c.isOnlyImportableAsDefault(moduleSpecifier, moduleSymbol) && ast.EscapeLeadingUnderscores(nameText) != ast.InternalSymbolNameDefault { c.error(name, diagnostics.Named_imports_from_a_JSON_file_into_an_ECMAScript_module_are_not_allowed_when_module_is_set_to_0, c.moduleKind.String()) } else if symbol == nil { c.errorNoModuleMemberSymbol(moduleSymbol, targetSymbol, node, name) @@ -14691,7 +14692,7 @@ func (c *Checker) getPropertyOfVariable(symbol *ast.Symbol, name string) *ast.Sy if symbol.Flags&ast.SymbolFlagsVariable != 0 { typeAnnotation := symbol.ValueDeclaration.Type() if typeAnnotation != nil { - return c.resolveSymbol(c.getPropertyOfType(c.getTypeFromTypeNode(typeAnnotation), name)) + return c.resolveSymbol(c.getPropertyOfType(c.getTypeFromTypeNode(typeAnnotation), ast.EscapeLeadingUnderscores(name))) } } return nil @@ -14740,9 +14741,10 @@ func (c *Checker) combineValueAndTypeSymbols(valueSymbol *ast.Symbol, typeSymbol func (c *Checker) getExportOfModule(symbol *ast.Symbol, nameText string, specifier *ast.Node, dontResolveAlias bool) *ast.Symbol { if symbol.Flags&ast.SymbolFlagsModule != 0 { - exportSymbol := c.getExportsOfSymbol(symbol)[nameText] + symbolName := ast.EscapeLeadingUnderscores(nameText) + exportSymbol := c.getExportsOfSymbol(symbol)[symbolName] resolved := c.resolveSymbolEx(exportSymbol, dontResolveAlias) - exportStarDeclaration := c.moduleSymbolLinks.Get(symbol).typeOnlyExportStarMap[nameText] + exportStarDeclaration := c.moduleSymbolLinks.Get(symbol).typeOnlyExportStarMap[symbolName] c.markSymbolOfAliasDeclarationIfTypeOnly(specifier, exportStarDeclaration) return resolved } @@ -14801,7 +14803,7 @@ func (c *Checker) canHaveSyntheticDefault(file *ast.Node, moduleSymbol *ast.Symb // Declaration files (and ambient modules) if file == nil || file.AsSourceFile().IsDeclarationFile { // Definitely cannot have a synthetic default if they have a syntactic default member specified - defaultExportSymbol := c.resolveExportByName(moduleSymbol, ast.InternalSymbolNameDefault /*sourceNode*/, nil /*dontResolveAlias*/, true) // Dont resolve alias because we want the immediately exported symbol's declaration + defaultExportSymbol := c.resolveExportByName(moduleSymbol, ast.UnescapeLeadingUnderscores(ast.InternalSymbolNameDefault) /*sourceNode*/, nil /*dontResolveAlias*/, true) // Dont resolve alias because we want the immediately exported symbol's declaration if defaultExportSymbol != nil && core.Some(defaultExportSymbol.Declarations, isSyntacticDefault) { return false } @@ -14861,7 +14863,7 @@ func (c *Checker) errorNoModuleMemberSymbol(moduleSymbol *ast.Symbol, targetSymb func (c *Checker) reportNonExportedMember(name *ast.Node, declarationName string, moduleSymbol *ast.Symbol, moduleName string) { var localSymbol *ast.Symbol if locals := moduleSymbol.ValueDeclaration.Locals(); locals != nil { - localSymbol = locals[name.Text()] + localSymbol = locals[ast.EscapeLeadingUnderscores(name.Text())] } exports := moduleSymbol.Exports if localSymbol != nil { @@ -15316,7 +15318,7 @@ func (c *Checker) resolveExternalModule(location *ast.Node, moduleReference stri if len(c.patternAmbientModules) != 0 { pattern := core.FindBestPatternMatch(c.patternAmbientModules, func(v *ast.PatternAmbientModule) core.Pattern { return v.Pattern }, moduleReference) if pattern != nil { - augmentation := c.patternAmbientModuleAugmentations[moduleReference] + augmentation := c.patternAmbientModuleAugmentations[ast.EscapeLeadingUnderscores(moduleReference)] if augmentation != nil { return c.getMergedSymbol(augmentation) } @@ -15497,7 +15499,8 @@ func (c *Checker) tryFindAmbientModule(moduleName string, withAugmentations bool func (c *Checker) GetAmbientModules() []*ast.Symbol { c.ambientModulesOnce.Do(func() { for sym, global := range c.globals { - if strings.HasPrefix(sym, "\"") && strings.HasSuffix(sym, "\"") { + name := ast.UnescapeLeadingUnderscores(sym) + if strings.HasPrefix(name, "\"") && strings.HasSuffix(name, "\"") { c.ambientModules = append(c.ambientModules, global) } } @@ -15549,7 +15552,7 @@ func (c *Checker) resolveESModuleSymbol(moduleSymbol *ast.Symbol, node *ast.Node core.ModuleKindNode20 <= c.moduleKind && c.moduleKind <= core.ModuleKindNodeNext && usageMode == core.ModuleKindCommonJS && c.program.GetImpliedNodeFormatForEmit(targetFile.AsSourceFile()) == core.ModuleKindESNext { - exportModuleDotExportsSymbol = c.getExportOfModule(symbol, ast.InternalSymbolNameModuleExports, namespaceImport, true /*dontResolveAlias*/) + exportModuleDotExportsSymbol = c.getExportOfModule(symbol, ast.UnescapeLeadingUnderscores(ast.InternalSymbolNameModuleExports), namespaceImport, true /*dontResolveAlias*/) } if exportModuleDotExportsSymbol != nil { if c.hasSignatures(typ) { @@ -15849,7 +15852,7 @@ func (c *Checker) tryGetQualifiedNameAsValue(node *ast.Node) *ast.Symbol { n := id for ast.IsQualifiedName(n.Parent) { t := c.getTypeOfSymbol(symbol) - symbol = c.getPropertyOfType(t, n.Parent.AsQualifiedName().Right.Text()) + symbol = c.getPropertyOfType(t, ast.EscapeLeadingUnderscores(n.Parent.AsQualifiedName().Right.Text())) if symbol == nil { return nil } @@ -15993,7 +15996,7 @@ func (c *Checker) lateBindMember(parent *ast.Symbol, earlySymbols ast.SymbolTabl } else { declarations = lateSymbol.Declarations } - name := memberName + name := ast.UnescapeLeadingUnderscores(memberName) if t.flags&TypeFlagsUniqueESSymbol != 0 { name = scanner.DeclarationNameToString(declName) } @@ -16095,11 +16098,11 @@ type ExportCollision struct { exportsWithDuplicate []*ast.Node } -type ExportCollisionTable = map[string]*ExportCollision +type ExportCollisionTable = map[ast.SymbolNameKey]*ExportCollision -func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports ast.SymbolTable, typeOnlyExportStarMap map[string]*ast.Node) { +func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports ast.SymbolTable, typeOnlyExportStarMap map[ast.SymbolNameKey]*ast.Node) { var visitedSymbols []*ast.Symbol - nonTypeOnlyNames := collections.NewSetWithSizeHint[string](len(moduleSymbol.Exports)) + nonTypeOnlyNames := collections.NewSetWithSizeHint[ast.SymbolNameKey](len(moduleSymbol.Exports)) // The ES6 spec permits export * declarations in a module to circularly reference the module itself. For example, // module 'a' can 'export * from "b"' and 'b' can 'export * from "a"' without error. var visit func(*ast.Symbol, *ast.Node, bool) ast.SymbolTable @@ -16133,14 +16136,14 @@ func (c *Checker) getExportsOfModuleWorker(moduleSymbol *ast.Symbol) (exports as continue } for _, node := range s.exportsWithDuplicate { - c.addDiagnostic(createDiagnosticForNode(node, diagnostics.Module_0_has_already_exported_a_member_named_1_Consider_explicitly_re_exporting_to_resolve_the_ambiguity, s.specifierText, id)) + c.addDiagnostic(createDiagnosticForNode(node, diagnostics.Module_0_has_already_exported_a_member_named_1_Consider_explicitly_re_exporting_to_resolve_the_ambiguity, s.specifierText, ast.UnescapeLeadingUnderscores(id))) } } c.extendExportSymbols(symbols, nestedSymbols, nil, nil) } if exportStar != nil && exportStar.IsTypeOnly() { if typeOnlyExportStarMap == nil { - typeOnlyExportStarMap = make(map[string]*ast.Node) + typeOnlyExportStarMap = make(map[ast.SymbolNameKey]*ast.Node) } for name := range symbols { typeOnlyExportStarMap[name] = exportStar @@ -16276,7 +16279,7 @@ func (c *Checker) resolveAliasWithDeprecationCheck(symbol *ast.Symbol, location } if len(target.Declarations) != 0 { if c.isDeprecatedSymbol(target) { - c.addDeprecatedSuggestion(location, target.Declarations, target.Name) + c.addDeprecatedSuggestion(location, target.Declarations, ast.UnescapeLeadingUnderscores(target.Name)) break } else { if symbol == targetSymbol { @@ -16799,7 +16802,7 @@ func (c *Checker) padObjectLiteralType(t *Type, pattern *ast.Node) *Type { return result } -func (c *Checker) getPropertyNameFromBindingElement(e *ast.Node) string { +func (c *Checker) getPropertyNameFromBindingElement(e *ast.Node) ast.SymbolNameKey { exprType := c.getLiteralTypeFromPropertyName(e.PropertyNameOrName()) if isTypeUsableAsPropertyName(exprType) { return getPropertyNameFromType(exprType) @@ -18399,13 +18402,13 @@ func (c *Checker) getWidenedProperty(prop *ast.Symbol, context *WideningContext) return c.createSymbolWithType(prop, widened) } -func (w *WideningContext) getChildContext(propertyName string) *WideningContext { +func (w *WideningContext) getChildContext(propertyName ast.SymbolNameKey) *WideningContext { if cached := w.childContexts[propertyName]; cached != nil { return cached } result := &WideningContext{parent: w, propertyName: propertyName} if w.childContexts == nil { - w.childContexts = make(map[string]*WideningContext) + w.childContexts = make(map[ast.SymbolNameKey]*WideningContext) } w.childContexts[propertyName] = result return result @@ -18417,7 +18420,7 @@ func (c *Checker) getPropertiesOfContext(context *WideningContext) []*ast.Symbol for _, t := range c.getSiblingsOfContext(context) { if isObjectLiteralType(t) && t.objectFlags&ObjectFlagsContainsSpread == 0 { for _, prop := range c.getPropertiesOfType(t) { - names.Set(prop.Name, prop) + names.Set(ast.UnescapeLeadingUnderscores(prop.Name), prop) } } } @@ -18656,7 +18659,7 @@ func (c *Checker) getEffectivePropertyNameForPropertyNameNode(node *ast.Property name := ast.GetPropertyNameForPropertyNameNode(node) switch { case name != ast.InternalSymbolNameMissing: - return name, true + return ast.UnescapeLeadingUnderscores(name), true case ast.IsComputedPropertyName(node): // This is cached so `getTypeOfExpression` isn't constantly reinvoked for every property name lookup links := c.computedNameLinks.Get(node) @@ -18674,7 +18677,7 @@ func (c *Checker) getEffectivePropertyNameForPropertyNameNode(node *ast.Property func (c *Checker) tryGetNameFromType(t *Type) (name string, ok bool) { switch { case t.flags&TypeFlagsUniqueESSymbol != 0: - return t.AsUniqueESSymbolType().name, true + return t.AsUniqueESSymbolType().name.EscapedText(), true case t.flags&TypeFlagsStringLiteral != 0: s := getStringLiteralValue(t) return s, true @@ -18813,7 +18816,7 @@ func (c *Checker) getPropertiesOfObjectType(t *Type) []*ast.Symbol { func (c *Checker) getPropertiesOfUnionOrIntersectionType(t *Type) []*ast.Symbol { d := t.AsUnionOrIntersectionType() if d.resolvedProperties == nil { - var checked collections.Set[string] + var checked collections.Set[ast.SymbolNameKey] props := []*ast.Symbol{} for _, current := range d.types { for _, prop := range c.getPropertiesOfType(current) { @@ -18836,7 +18839,7 @@ func (c *Checker) getPropertiesOfUnionOrIntersectionType(t *Type) []*ast.Symbol return d.resolvedProperties } -func (c *Checker) getPropertyOfType(t *Type, name string) *ast.Symbol { +func (c *Checker) getPropertyOfType(t *Type, name ast.SymbolNameKey) *ast.Symbol { return c.getPropertyOfTypeEx(t, name, false /*skipObjectFunctionPropertyAugment*/, false /*includeTypeOnlyMembers*/) } @@ -18848,7 +18851,7 @@ func (c *Checker) getPropertyOfType(t *Type, name string) *ast.Symbol { * @param type a type to look up property from * @param name a name of property to look up in a given type */ -func (c *Checker) getPropertyOfTypeEx(t *Type, name string, skipObjectFunctionPropertyAugment bool, includeTypeOnlyMembers bool) *ast.Symbol { +func (c *Checker) getPropertyOfTypeEx(t *Type, name ast.SymbolNameKey, skipObjectFunctionPropertyAugment bool, includeTypeOnlyMembers bool) *ast.Symbol { t = c.getReducedApparentType(t) switch { case t.flags&TypeFlagsObject != 0: @@ -18900,7 +18903,7 @@ func (c *Checker) getPropertyOfTypeEx(t *Type, name string, skipObjectFunctionPr } // Return the type of the given property in the given type, or nil if no such property exists -func (c *Checker) getTypeOfPropertyOfType(t *Type, name string) *Type { +func (c *Checker) getTypeOfPropertyOfType(t *Type, name ast.SymbolNameKey) *Type { prop := c.getPropertyOfType(t, name) if prop != nil { return c.getTypeOfSymbol(prop) @@ -18961,11 +18964,11 @@ func (c *Checker) getApplicableIndexInfo(t *Type, keyType *Type) *IndexInfo { return c.findApplicableIndexInfo(c.getIndexInfosOfType(t), keyType) } -func (c *Checker) getApplicableIndexInfoForName(t *Type, name string) *IndexInfo { +func (c *Checker) getApplicableIndexInfoForName(t *Type, name ast.SymbolNameKey) *IndexInfo { if isLateBoundName(name) { return c.getApplicableIndexInfo(t, c.esSymbolType) } - return c.getApplicableIndexInfo(t, c.getStringLiteralType(name)) + return c.getApplicableIndexInfo(t, c.getStringLiteralType(ast.UnescapeLeadingUnderscores(name))) } func (c *Checker) findApplicableIndexInfo(indexInfos []*IndexInfo, keyType *Type) *IndexInfo { @@ -19702,7 +19705,7 @@ func (c *Checker) isSymbolWithSymbolName(symbol *ast.Symbol) bool { } func (c *Checker) isSymbolWithNumericName(symbol *ast.Symbol) bool { - if isNumericLiteralName(symbol.Name) { + if isNumericLiteralName(ast.UnescapeLeadingUnderscores(symbol.Name)) { return true } if len(symbol.Declarations) != 0 { @@ -19809,7 +19812,7 @@ func (c *Checker) getSignatureFromDeclaration(declaration *ast.Node) *Signature typeNode := param.Type() // Include parameter symbol instead of property symbol in the signature if paramSymbol != nil && paramSymbol.Flags&ast.SymbolFlagsProperty != 0 && !ast.IsBindingPattern(param.Name()) { - resolvedSymbol := c.resolveName(param, paramSymbol.Name, ast.SymbolFlagsValue, nil /*nameNotFoundMessage*/, false /*isUse*/, false /*excludeGlobals*/) + resolvedSymbol := c.resolveName(param, ast.UnescapeLeadingUnderscores(paramSymbol.Name), ast.SymbolFlagsValue, nil /*nameNotFoundMessage*/, false /*isUse*/, false /*excludeGlobals*/) paramSymbol = resolvedSymbol } if i == 0 && paramSymbol.Name == ast.InternalSymbolNameThis { @@ -21022,7 +21025,7 @@ func (c *Checker) resolveUnionTypeMembers(t *Type) { func (c *Checker) getArrayMemberCallSignatures(t *Type) []*Signature { // Check if union is exclusively instantiations of a member of the global Array or ReadonlyArray type. - var memberName string + var memberName ast.SymbolNameKey for i, t := range t.Types() { if t.objectFlags&ObjectFlagsInstantiated == 0 || t.symbol == nil || t.symbol.Parent == nil || !c.isArrayOrTupleSymbol(t.symbol.Parent) { return nil @@ -21215,7 +21218,7 @@ func (c *Checker) combineUnionOrIntersectionParameters(left *Signature, right *S if paramName == "" { paramName = "arg" + strconv.Itoa(i) } - paramSymbol := c.newSymbolEx(ast.SymbolFlagsFunctionScopedVariable|core.IfElse(isOptional && !isRestParam, ast.SymbolFlagsOptional, 0), paramName, + paramSymbol := c.newSymbolEx(ast.SymbolFlagsFunctionScopedVariable|core.IfElse(isOptional && !isRestParam, ast.SymbolFlagsOptional, 0), ast.EscapeLeadingUnderscores(paramName), core.IfElse(isRestParam, ast.CheckFlagsRestParameter, core.IfElse(isOptional, ast.CheckFlagsOptionalParameter, 0))) links := c.valueSymbolLinks.Get(paramSymbol) if isRestParam { @@ -21352,7 +21355,7 @@ func (c *Checker) includeMixinType(t *Type, types []*Type, mixinFlags []bool, in * If the given type is an object type and that type has a property by the given name, * return the symbol for that property. Otherwise return undefined. */ -func (c *Checker) getPropertyOfObjectType(t *Type, name string) *ast.Symbol { +func (c *Checker) getPropertyOfObjectType(t *Type, name ast.SymbolNameKey) *ast.Symbol { if t.flags&TypeFlagsObject != 0 { resolved := c.resolveStructuredTypeMembers(t) symbol := resolved.members[name] @@ -21363,7 +21366,7 @@ func (c *Checker) getPropertyOfObjectType(t *Type, name string) *ast.Symbol { return nil } -func (c *Checker) getPropertyOfUnionOrIntersectionType(t *Type, name string, skipObjectFunctionPropertyAugment bool) *ast.Symbol { +func (c *Checker) getPropertyOfUnionOrIntersectionType(t *Type, name ast.SymbolNameKey, skipObjectFunctionPropertyAugment bool) *ast.Symbol { prop := c.getUnionOrIntersectionProperty(t, name, skipObjectFunctionPropertyAugment) // We need to filter out partial properties in union types if prop != nil && prop.CheckFlags&ast.CheckFlagsReadPartial != 0 { @@ -21377,7 +21380,7 @@ func (c *Checker) getPropertyOfUnionOrIntersectionType(t *Type, name string, ski // constituents, in which case the isPartial flag is set when the containing type is union type. We need // these partial properties when identifying discriminant properties, but otherwise they are filtered out // and do not appear to be present in the union type. -func (c *Checker) getUnionOrIntersectionProperty(t *Type, name string, skipObjectFunctionPropertyAugment bool) *ast.Symbol { +func (c *Checker) getUnionOrIntersectionProperty(t *Type, name ast.SymbolNameKey, skipObjectFunctionPropertyAugment bool) *ast.Symbol { var cache ast.SymbolTable if skipObjectFunctionPropertyAugment { cache = ast.GetSymbolTable(&t.AsUnionOrIntersectionType().propertyCacheWithoutFunctionPropertyAugment) @@ -21401,7 +21404,7 @@ func (c *Checker) getUnionOrIntersectionProperty(t *Type, name string, skipObjec return prop } -func (c *Checker) createUnionOrIntersectionProperty(containingType *Type, name string, skipObjectFunctionPropertyAugment bool) *ast.Symbol { +func (c *Checker) createUnionOrIntersectionProperty(containingType *Type, name ast.SymbolNameKey, skipObjectFunctionPropertyAugment bool) *ast.Symbol { propFlags := ast.SymbolFlagsNone var singleProp *ast.Symbol var propSet collections.OrderedSet[*ast.Symbol] @@ -22036,7 +22039,7 @@ func (c *Checker) isDeclarationContainedBy(symbol *ast.Symbol, container *ast.Sy return false } -func (c *Checker) isNamedMember(symbol *ast.Symbol, id string) bool { +func (c *Checker) isNamedMember(symbol *ast.Symbol, id ast.SymbolNameKey) bool { return !isReservedMemberName(id) && c.symbolIsValue(symbol) } @@ -22938,13 +22941,8 @@ func (c *Checker) getESSymbolLikeTypeForNode(node *ast.Node) *Type { if symbol != nil { uniqueType := c.uniqueESSymbolTypes[symbol] if uniqueType == nil { - var b strings.Builder - b.WriteString(ast.InternalSymbolNamePrefix) - b.WriteByte('@') - b.WriteString(symbol.Name) - b.WriteByte('@') - b.WriteString(strconv.FormatUint(uint64(ast.GetSymbolId(symbol)), 10)) - uniqueType = c.newUniqueESSymbolType(symbol, b.String()) + name := ast.InternalSymbolName("@" + symbol.Name.EscapedText() + "@" + strconv.FormatUint(uint64(ast.GetSymbolId(symbol)), 10)) + uniqueType = c.newUniqueESSymbolType(symbol, name) c.uniqueESSymbolTypes[symbol] = uniqueType } return uniqueType @@ -23081,7 +23079,7 @@ func (c *Checker) getUnresolvedSymbolForEntityName(name *ast.Node) *ast.Symbol { } result := c.unresolvedSymbols[path] if result == nil { - result = c.newSymbolEx(ast.SymbolFlagsTypeAlias, text, ast.CheckFlagsUnresolved) + result = c.newSymbolEx(ast.SymbolFlagsTypeAlias, ast.EscapeLeadingUnderscores(text), ast.CheckFlagsUnresolved) c.unresolvedSymbols[path] = result result.Parent = parentSymbol c.typeAliasLinks.Get(result).declaredType = c.unresolvedType @@ -23093,9 +23091,9 @@ func (c *Checker) getUnresolvedSymbolForEntityName(name *ast.Node) *ast.Symbol { func getSymbolPath(symbol *ast.Symbol) string { if symbol.Parent != nil { - return getSymbolPath(symbol.Parent) + "." + symbol.Name + return getSymbolPath(symbol.Parent) + "." + symbol.Name.EscapedText() } - return symbol.Name + return symbol.Name.EscapedText() } func (c *Checker) getTypeReferenceType(node *ast.Node, symbol *ast.Symbol) *Type { @@ -23517,7 +23515,7 @@ func (c *Checker) isArrayOrTupleOrIntersection(t *Type) bool { } func (c *Checker) getTupleElementType(t *Type, index int) *Type { - propType := c.getTypeOfPropertyOfType(t, strconv.Itoa(index)) + propType := c.getTypeOfPropertyOfType(t, ast.EscapeLeadingUnderscores(strconv.Itoa(index))) if propType != nil { return propType } @@ -23596,7 +23594,7 @@ func (c *Checker) getTypeFromTypeAliasReference(node *ast.Node, symbol *ast.Symb func (c *Checker) getTypeAliasInstantiation(symbol *ast.Symbol, typeArguments []*Type, alias *TypeAlias) *Type { t := c.getDeclaredTypeOfSymbol(symbol) if t == c.intrinsicMarkerType { - if typeKind, ok := intrinsicTypeKinds[symbol.Name]; ok && len(typeArguments) == 1 { + if typeKind, ok := intrinsicTypeKinds[ast.UnescapeLeadingUnderscores(symbol.Name)]; ok && len(typeArguments) == 1 { switch typeKind { case IntrinsicTypeKindNoInfer: return c.getNoInferType(typeArguments[0]) @@ -24015,7 +24013,7 @@ func (c *Checker) evaluateEntity(expr *ast.Node, location *ast.Node) evaluator.R rootSymbol := c.resolveEntityName(root, ast.SymbolFlagsValue, true /*ignoreErrors*/, false, nil) if rootSymbol != nil && rootSymbol.Flags&ast.SymbolFlagsEnum != 0 { name := expr.AsElementAccessExpression().ArgumentExpression.Text() - member := rootSymbol.Exports[name] + member := rootSymbol.Exports[ast.EscapeLeadingUnderscores(name)] if member != nil { if location != nil { return c.evaluateEnumMember(expr, member, location) @@ -24561,7 +24559,7 @@ func (c *Checker) getTypeFromImportTypeNode(node *ast.Node) *Type { var symbolFromVariable *ast.Symbol var symbolFromModule *ast.Symbol if n.IsTypeOf { - symbolFromVariable = c.getPropertyOfTypeEx(c.getTypeOfSymbol(mergedResolvedSymbol), current.Text(), false /*skipObjectFunctionPropertyAugment*/, true /*includeTypeOnlyMembers*/) + symbolFromVariable = c.getPropertyOfTypeEx(c.getTypeOfSymbol(mergedResolvedSymbol), ast.EscapeLeadingUnderscores(current.Text()), false /*skipObjectFunctionPropertyAugment*/, true /*includeTypeOnlyMembers*/) } else { symbolFromModule = c.getSymbol(c.getExportsOfSymbol(mergedResolvedSymbol), current.Text(), meaning) if symbolFromModule == nil { @@ -24743,7 +24741,7 @@ func (c *Checker) createTupleTargetType(elementInfos []TupleElementInfo, readonl flags := elementInfos[i].flags combinedFlags |= flags if combinedFlags&ElementFlagsVariable == 0 { - property := c.newSymbolEx(ast.SymbolFlagsProperty|core.IfElse(flags&ElementFlagsOptional != 0, ast.SymbolFlagsOptional, 0), strconv.Itoa(i), core.IfElse(readonly, ast.CheckFlagsReadonly, 0)) + property := c.newSymbolEx(ast.SymbolFlagsProperty|core.IfElse(flags&ElementFlagsOptional != 0, ast.SymbolFlagsOptional, 0), ast.EscapeLeadingUnderscores(strconv.Itoa(i)), core.IfElse(readonly, ast.CheckFlagsReadonly, 0)) c.valueSymbolLinks.Get(property).resolvedType = typeParameter // c.valueSymbolLinks.get(property).tupleLabelDeclaration = elementInfos[i].labeledDeclaration members[property.Name] = property @@ -25007,7 +25005,7 @@ func (c *Checker) newLiteralType(flags TypeFlags, value any, regularType *Type) return t } -func (c *Checker) newUniqueESSymbolType(symbol *ast.Symbol, name string) *Type { +func (c *Checker) newUniqueESSymbolType(symbol *ast.Symbol, name ast.SymbolNameKey) *Type { data := &UniqueESSymbolType{} data.name = name t := c.newType(TypeFlagsUniqueESSymbol, ObjectFlagsNone, data) @@ -26710,7 +26708,7 @@ func (c *Checker) getLiteralTypeFromPropertyName(name *ast.Node) *Type { } propertyName := ast.GetPropertyNameForPropertyNameNode(name) if propertyName != ast.InternalSymbolNameMissing { - return c.getStringLiteralType(propertyName) + return c.getStringLiteralType(ast.UnescapeLeadingUnderscores(propertyName)) } if ast.IsExpression(name) { return c.getRegularTypeOfLiteralType(c.checkExpression(name)) @@ -26935,7 +26933,7 @@ func (c *Checker) getPropertyTypeForIndexType(originalObjectType *Type, objectTy if accessNode != nil && ast.IsElementAccessExpression(accessNode) { accessExpression = accessNode } - var propName string + var propName ast.SymbolNameKey var hasPropName bool if !(accessNode != nil && ast.IsPrivateIdentifier(accessNode)) { propName = c.getPropertyNameFromIndex(indexType, accessNode) @@ -26960,7 +26958,7 @@ func (c *Checker) getPropertyTypeForIndexType(originalObjectType *Type, objectTy } else { deprecatedNode = accessNode } - c.addDeprecatedSuggestion(deprecatedNode, prop.Declarations, propName) + c.addDeprecatedSuggestion(deprecatedNode, prop.Declarations, ast.UnescapeLeadingUnderscores(propName)) } if accessExpression != nil { c.markPropertyAsReferenced(prop, accessExpression, c.isSelfTypeAccess(accessExpression.Expression(), objectType.symbol)) @@ -26990,8 +26988,8 @@ func (c *Checker) getPropertyTypeForIndexType(originalObjectType *Type, objectTy return propType } } - if everyType(objectType, isTupleType) && isNumericLiteralName(propName) { - index := jsnum.FromString(propName) + if everyType(objectType, isTupleType) && isNumericLiteralName(ast.UnescapeLeadingUnderscores(propName)) { + index := jsnum.FromString(ast.UnescapeLeadingUnderscores(propName)) if accessNode != nil && everyType(objectType, func(t *Type) bool { return t.TargetTupleType().combinedFlags&ElementFlagsVariable == 0 }) && accessFlags&AccessFlagsAllowMissing == 0 { @@ -27075,20 +27073,20 @@ func (c *Checker) getPropertyTypeForIndexType(originalObjectType *Type, objectTy } } if objectType.symbol == c.globalThisSymbol && hasPropName && c.globalThisSymbol.Exports[propName] != nil && c.globalThisSymbol.Exports[propName].Flags&ast.SymbolFlagsBlockScoped != 0 { - c.error(accessExpression, diagnostics.Property_0_does_not_exist_on_type_1, propName, c.TypeToString(objectType)) + c.error(accessExpression, diagnostics.Property_0_does_not_exist_on_type_1, ast.UnescapeLeadingUnderscores(propName), c.TypeToString(objectType)) } else if c.noImplicitAny && accessFlags&AccessFlagsSuppressNoImplicitAnyError == 0 { - if hasPropName && c.typeHasStaticProperty(propName, objectType) { + if hasPropName && c.typeHasStaticProperty(ast.UnescapeLeadingUnderscores(propName), objectType) { typeName := c.TypeToString(objectType) - c.error(accessExpression, diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_to_access_the_static_member_2_instead, propName /* as string */, typeName, typeName+"["+scanner.GetTextOfNode(accessExpression.AsElementAccessExpression().ArgumentExpression)+"]") + c.error(accessExpression, diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_to_access_the_static_member_2_instead, ast.UnescapeLeadingUnderscores(propName), typeName, typeName+"["+scanner.GetTextOfNode(accessExpression.AsElementAccessExpression().ArgumentExpression)+"]") } else if c.getIndexTypeOfType(objectType, c.numberType) != nil { c.error(accessExpression.AsElementAccessExpression().ArgumentExpression, diagnostics.Element_implicitly_has_an_any_type_because_index_expression_is_not_of_type_number) } else { var suggestion string if hasPropName { - suggestion = c.getSuggestionForNonexistentProperty(propName, objectType) + suggestion = c.getSuggestionForNonexistentProperty(ast.UnescapeLeadingUnderscores(propName), objectType) } if suggestion != "" { - c.error(accessExpression.AsElementAccessExpression().ArgumentExpression, diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, propName /* as string */, c.TypeToString(objectType), suggestion) + c.error(accessExpression.AsElementAccessExpression().ArgumentExpression, diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, ast.UnescapeLeadingUnderscores(propName), c.TypeToString(objectType), suggestion) } else { suggestion = c.getSuggestionForNonexistentIndexSignature(objectType, accessExpression, indexType) if suggestion != "" { @@ -27146,7 +27144,7 @@ func (c *Checker) getPropertyTypeForIndexType(originalObjectType *Type, objectTy func (c *Checker) typeHasStaticProperty(propName string, containingType *Type) bool { if containingType.symbol != nil { - prop := c.getPropertyOfType(c.getTypeOfSymbol(containingType.symbol), propName) + prop := c.getPropertyOfType(c.getTypeOfSymbol(containingType.symbol), ast.EscapeLeadingUnderscores(propName)) return prop != nil && prop.ValueDeclaration != nil && ast.IsStatic(prop.ValueDeclaration) } return false @@ -27155,7 +27153,7 @@ func (c *Checker) typeHasStaticProperty(propName string, containingType *Type) b func (c *Checker) getSuggestionForNonexistentProperty(name string, containingType *Type) string { symbol := c.getSpellingSuggestionForName(name, slices.Values(c.getPropertiesOfType(containingType)), ast.SymbolFlagsValue) if symbol != nil { - return symbol.Name + return ast.UnescapeLeadingUnderscores(symbol.Name) } return "" } @@ -27163,7 +27161,7 @@ func (c *Checker) getSuggestionForNonexistentProperty(name string, containingTyp func (c *Checker) getSuggestionForNonexistentIndexSignature(objectType *Type, expr *ast.Node, keyedType *Type) string { // check if object type has setter or getter hasProp := func(name string) bool { - prop := c.getPropertyOfObjectType(objectType, name) + prop := c.getPropertyOfObjectType(objectType, ast.EscapeLeadingUnderscores(name)) if prop != nil { s := c.getSingleCallSignature(c.getTypeOfSymbol(prop)) return s != nil && c.getMinArgumentCount(s) >= 1 && c.isTypeAssignableTo(keyedType, c.getTypeAtPosition(s, 0)) @@ -27284,7 +27282,7 @@ func (c *Checker) getDeclaringConstructor(symbol *ast.Symbol) *ast.Node { return nil } -func (c *Checker) getPropertyNameFromIndex(indexType *Type, accessNode *ast.Node) string { +func (c *Checker) getPropertyNameFromIndex(indexType *Type, accessNode *ast.Node) ast.SymbolNameKey { if isTypeUsableAsPropertyName(indexType) { return getPropertyNameFromType(indexType) } @@ -27314,8 +27312,8 @@ func indexTypeLessThan(indexType *Type, limit int) bool { return everyType(indexType, func(t *Type) bool { if t.flags&TypeFlagsStringOrNumberLiteral != 0 { propName := getPropertyNameFromType(t) - if isNumericLiteralName(propName) { - index := jsnum.FromString(propName) + if isNumericLiteralName(ast.UnescapeLeadingUnderscores(propName)) { + index := jsnum.FromString(ast.UnescapeLeadingUnderscores(propName)) return index >= 0 && index < jsnum.Number(limit) } } @@ -27675,7 +27673,7 @@ func (c *Checker) expandSignatureParametersWithTupleMembers(signature *Signature case flags&ElementFlagsOptional != 0: checkFlags = ast.CheckFlagsOptionalParameter } - symbol := c.newSymbolEx(ast.SymbolFlagsFunctionScopedVariable, associatedNames[i], checkFlags) + symbol := c.newSymbolEx(ast.SymbolFlagsFunctionScopedVariable, ast.EscapeLeadingUnderscores(associatedNames[i]), checkFlags) links := c.valueSymbolLinks.Get(symbol) if flags&ElementFlagsRest != 0 { links.resolvedType = c.createArrayType(t) @@ -28391,7 +28389,7 @@ func (c *Checker) markPropertyAliasReferenced(location *ast.Node /*PropertyAcces prop = c.getPrivateIdentifierPropertyOfType(apparentType, lexicallyScopedSymbol) } } else { - prop = c.getPropertyOfType(apparentType, right.Text()) + prop = c.getPropertyOfType(apparentType, ast.EscapeLeadingUnderscores(right.Text())) } } if !(prop != nil && (isConstEnumOrConstEnumOnlyModule(prop) || prop.Flags&ast.SymbolFlagsEnumMember != 0 && location.Parent.Kind == ast.KindEnumMember)) { @@ -29163,7 +29161,7 @@ func (c *Checker) getStringMappingType(symbol *ast.Symbol, t *Type) *Type { } func applyStringMapping(symbol *ast.Symbol, str string) string { - switch intrinsicTypeKinds[symbol.Name] { + switch intrinsicTypeKinds[ast.UnescapeLeadingUnderscores(symbol.Name)] { case IntrinsicTypeKindUppercase: return stringutil.ToUpperJS(str) case IntrinsicTypeKindLowercase: @@ -29179,7 +29177,7 @@ func applyStringMapping(symbol *ast.Symbol, str string) string { } func (c *Checker) applyTemplateStringMapping(symbol *ast.Symbol, texts []string, types []*Type) ([]string, []*Type) { - switch intrinsicTypeKinds[symbol.Name] { + switch intrinsicTypeKinds[ast.UnescapeLeadingUnderscores(symbol.Name)] { case IntrinsicTypeKindUppercase, IntrinsicTypeKindLowercase: return core.Map(texts, func(t string) string { return applyStringMapping(symbol, t) }), core.Map(types, func(t *Type) *Type { return c.getStringMappingType(symbol, t) }) @@ -29235,11 +29233,11 @@ func (c *Checker) couldAccessOptionalProperty(objectType *Type, indexType *Type) } func (c *Checker) getTypeOfPropertyOrIndexSignatureOfType(t *Type, name string) *Type { - propType := c.getTypeOfPropertyOfType(t, name) + propType := c.getTypeOfPropertyOfType(t, ast.EscapeLeadingUnderscores(name)) if propType != nil { return propType } - indexInfo := c.getApplicableIndexInfoForName(t, name) + indexInfo := c.getApplicableIndexInfoForName(t, ast.EscapeLeadingUnderscores(name)) if indexInfo != nil { return c.addOptionalityEx(indexInfo.valueType, true /*isProperty*/, true /*isOptional*/) } @@ -29782,7 +29780,7 @@ func (c *Checker) getContextualTypeForAssignmentExpression(binary *ast.BinaryExp if symbol.ValueDeclaration != nil && ast.IsVariableDeclaration(symbol.ValueDeclaration) { if typeNode := symbol.ValueDeclaration.Type(); typeNode != nil { if ast.IsPropertyAccessExpression(left) { - return c.getTypeOfPropertyOfContextualType(c.getTypeFromTypeNode(typeNode), left.Name().Text()) + return c.getTypeOfPropertyOfContextualType(c.getTypeFromTypeNode(typeNode), ast.EscapeLeadingUnderscores(left.Name().Text())) } nameType := c.checkExpressionCached(left.AsElementAccessExpression().ArgumentExpression) if isTypeUsableAsPropertyName(nameType) { @@ -29807,7 +29805,7 @@ func (c *Checker) getContextualTypeForAssignmentExpression(binary *ast.BinaryExp symbol = c.getPropertyOfType(thisType, binder.GetSymbolNameForPrivateIdentifier(thisType.symbol, name.Text())) } } else { - symbol = c.getPropertyOfType(thisType, name.Text()) + symbol = c.getPropertyOfType(thisType, ast.EscapeLeadingUnderscores(name.Text())) } } else { propType := c.checkExpressionCached(left.AsElementAccessExpression().ArgumentExpression) @@ -29932,7 +29930,7 @@ func (c *Checker) getContextualTypeForElementExpression(t *Type, index int, leng // If element index is known and a contextual property with that name exists, return it. Otherwise return the // iterated or element type of the contextual type. if firstSpreadIndex < 0 || index < firstSpreadIndex { - propType := c.getTypeOfPropertyOfContextualType(t, strconv.Itoa(index)) + propType := c.getTypeOfPropertyOfContextualType(t, ast.EscapeLeadingUnderscores(strconv.Itoa(index))) if propType != nil { return propType } @@ -29958,7 +29956,7 @@ func (c *Checker) getContextualTypeForSubstitutionExpression(template *ast.Node, } func (c *Checker) getContextualImportAttributeType(node *ast.Node) *Type { - return c.getTypeOfPropertyOfContextualType(c.getGlobalImportAttributesType(), node.Name().Text()) + return c.getTypeOfPropertyOfContextualType(c.getGlobalImportAttributesType(), ast.EscapeLeadingUnderscores(node.Name().Text())) } // Returns the effective arguments for an expression that works like a function invocation. @@ -30471,11 +30469,11 @@ func (c *Checker) getClassElementPropertyKeyType(element *ast.Node) *Type { return c.errorType } -func (c *Checker) getTypeOfPropertyOfContextualType(t *Type, name string) *Type { +func (c *Checker) getTypeOfPropertyOfContextualType(t *Type, name ast.SymbolNameKey) *Type { return c.getTypeOfPropertyOfContextualTypeEx(t, name, nil) } -func (c *Checker) getTypeOfPropertyOfContextualTypeEx(t *Type, name string, nameType *Type) *Type { +func (c *Checker) getTypeOfPropertyOfContextualTypeEx(t *Type, name ast.SymbolNameKey, nameType *Type) *Type { return c.mapTypeEx(t, func(t *Type) *Type { if t.flags&TypeFlagsIntersection != 0 { var types []*Type @@ -30527,10 +30525,10 @@ func (c *Checker) getTypeOfPropertyOfContextualTypeEx(t *Type, name string, name }, true /*noReductions*/) } -func (c *Checker) getIndexedMappedTypeSubstitutedTypeOfContextualType(t *Type, name string, nameType *Type) *Type { +func (c *Checker) getIndexedMappedTypeSubstitutedTypeOfContextualType(t *Type, name ast.SymbolNameKey, nameType *Type) *Type { propertyNameType := nameType if propertyNameType == nil { - propertyNameType = c.getStringLiteralType(name) + propertyNameType = c.getStringLiteralType(ast.UnescapeLeadingUnderscores(name)) } constraint := c.getConstraintTypeFromMappedType(t) // special case for conditional types pretending to be negated types @@ -30558,7 +30556,7 @@ func (c *Checker) isExcludedMappedPropertyName(t *Type, propertyNameType *Type) return false } -func (c *Checker) getTypeOfConcretePropertyOfContextualType(t *Type, name string) *Type { +func (c *Checker) getTypeOfConcretePropertyOfContextualType(t *Type, name ast.SymbolNameKey) *Type { prop := c.getPropertyOfType(t, name) if prop == nil || c.isCircularMappedProperty(prop) { return nil @@ -30566,15 +30564,16 @@ func (c *Checker) getTypeOfConcretePropertyOfContextualType(t *Type, name string return c.removeMissingType(c.getTypeOfSymbol(prop), prop.Flags&ast.SymbolFlagsOptional != 0) } -func (c *Checker) getTypeFromIndexInfosOfContextualType(t *Type, name string, nameType *Type) *Type { - if isTupleType(t) && isNumericLiteralName(name) && jsnum.FromString(name) >= 0 { +func (c *Checker) getTypeFromIndexInfosOfContextualType(t *Type, name ast.SymbolNameKey, nameType *Type) *Type { + nameText := ast.UnescapeLeadingUnderscores(name) + if isTupleType(t) && isNumericLiteralName(nameText) && jsnum.FromString(nameText) >= 0 { restType := c.getElementTypeOfSliceOfTupleType(t, t.TargetTupleType().fixedLength, 0 /*endSkipCount*/, false /*writing*/, true /*noReductions*/) if restType != nil { return restType } } if nameType == nil { - nameType = c.getStringLiteralType(name) + nameType = c.getStringLiteralType(nameText) } indexInfo := c.findApplicableIndexInfo(c.getIndexInfosOfStructuredType(t), nameType) if indexInfo == nil { @@ -30645,9 +30644,9 @@ func (d *ObjectLiteralDiscriminator) len() int { func (d *ObjectLiteralDiscriminator) name(index int) string { if index < len(d.props) { - return d.props[index].Symbol().Name + return ast.UnescapeLeadingUnderscores(d.props[index].Symbol().Name) } - return d.members[index-len(d.props)].Name + return ast.UnescapeLeadingUnderscores(d.members[index-len(d.props)].Name) } func (d *ObjectLiteralDiscriminator) matches(index int, t *Type) bool { @@ -31545,7 +31544,7 @@ func (c *Checker) getSymbolAtLocation(node *ast.Node, ignoreErrors bool) *ast.Sy return c.getSymbolOfNameOrPropertyAccessExpression(node) } else if ast.IsBindingElement(parent) && ast.IsObjectBindingPattern(grandParent) && node == parent.PropertyName() { typeOfPattern := c.getTypeOfNode(grandParent) - if propertyDeclaration := c.getPropertyOfType(typeOfPattern, node.Text()); propertyDeclaration != nil { + if propertyDeclaration := c.getPropertyOfType(typeOfPattern, ast.EscapeLeadingUnderscores(node.Text())); propertyDeclaration != nil { return propertyDeclaration } } else if ast.IsMetaProperty(parent) && parent.Name() == node { @@ -31630,7 +31629,7 @@ func (c *Checker) getSymbolAtLocation(node *ast.Node, ignoreErrors bool) *ast.Sy } if objectType != nil { - return c.getPropertyOfType(objectType, node.Text()) + return c.getPropertyOfType(objectType, ast.EscapeLeadingUnderscores(node.Text())) } return nil case ast.KindDefaultKeyword, ast.KindFunctionKeyword, ast.KindEqualsGreaterThanToken, ast.KindClassKeyword: @@ -31783,7 +31782,7 @@ func (c *Checker) getSymbolOfNameOrPropertyAccessExpression(name *ast.Node) *ast symbol := c.getSymbolOfDeclaration(container) // Handle unqualified references to class static members and class or interface instance members if result = c.getMergedSymbol(c.getSymbol(c.getExportsOfSymbol(symbol), name.Text(), meaning)); result == nil { - result = c.getPropertyOfType(c.getDeclaredTypeOfSymbol(symbol), name.Text()) + result = c.getPropertyOfType(c.getDeclaredTypeOfSymbol(symbol), ast.EscapeLeadingUnderscores(name.Text())) } } } @@ -32054,7 +32053,7 @@ func (c *Checker) containsArgumentsReference(node *ast.Node) bool { } switch node.Kind { case ast.KindIdentifier: - return node.Text() == c.argumentsSymbol.Name && c.IsArgumentsSymbol(c.getResolvedSymbol(node)) + return ast.EscapeLeadingUnderscores(node.Text()) == c.argumentsSymbol.Name && c.IsArgumentsSymbol(c.getResolvedSymbol(node)) case ast.KindPropertyDeclaration, ast.KindMethodDeclaration, ast.KindGetAccessor, ast.KindSetAccessor: if ast.IsComputedPropertyName(node.Name()) { return visit(node.Name()) diff --git a/internal/checker/exports.go b/internal/checker/exports.go index 5fa454ff737..9b83a9f9491 100644 --- a/internal/checker/exports.go +++ b/internal/checker/exports.go @@ -90,7 +90,7 @@ func IsTypeUsableAsPropertyName(t *Type) bool { } func GetPropertyNameFromType(t *Type) string { - return getPropertyNameFromType(t) + return ast.UnescapeLeadingUnderscores(getPropertyNameFromType(t)) } func (c *Checker) GetGlobalSymbol(name string, meaning ast.SymbolFlags, diagnostic *diagnostics.Message) *ast.Symbol { @@ -134,7 +134,7 @@ func (c *Checker) GetPropertiesOfType(t *Type) []*ast.Symbol { } func (c *Checker) GetPropertyOfType(t *Type, name string) *ast.Symbol { - return c.getPropertyOfType(t, name) + return c.getPropertyOfType(t, ast.EscapeLeadingUnderscores(name)) } func (c *Checker) TypeHasCallOrConstructSignatures(t *Type) bool { @@ -154,7 +154,7 @@ func (c *Checker) IsPropertyAccessible(node *ast.Node, isSuper bool, isWrite boo } func (c *Checker) GetTypeOfPropertyOfContextualType(t *Type, name string) *Type { - return c.getTypeOfPropertyOfContextualType(t, name) + return c.getTypeOfPropertyOfContextualType(t, ast.EscapeLeadingUnderscores(name)) } func GetDeclarationModifierFlagsFromSymbol(s *ast.Symbol) ast.ModifierFlags { @@ -247,7 +247,7 @@ func (c *Checker) GetResolvedSignature(node *ast.Node) *Signature { // Return the type of the given property in the given type, or nil if no such property exists func (c *Checker) GetTypeOfPropertyOfType(t *Type, name string) *Type { - return c.getTypeOfPropertyOfType(t, name) + return c.getTypeOfPropertyOfType(t, ast.EscapeLeadingUnderscores(name)) } func (c *Checker) GetContextualTypeForArgumentAtIndex(node *ast.Node, argIndex int) *Type { diff --git a/internal/checker/flow.go b/internal/checker/flow.go index e889fb21755..e0421a141c3 100644 --- a/internal/checker/flow.go +++ b/internal/checker/flow.go @@ -523,7 +523,7 @@ func (c *Checker) narrowTypeByBinaryExpression(f *FlowState, t *Type, expr *ast. if c.containsMissingType(t) && ast.IsAccessExpression(f.reference) && c.isMatchingReference(f.reference.Expression(), target) { leftType := c.getTypeOfExpression(expr.Left) if isTypeUsableAsPropertyName(leftType) { - if accessedName, ok := c.getAccessedPropertyName(f.reference); ok && accessedName == getPropertyNameFromType(leftType) { + if accessedName, ok := c.getAccessedPropertyName(f.reference); ok && accessedName == ast.UnescapeLeadingUnderscores(getPropertyNameFromType(leftType)) { return c.getTypeWithFacts(t, core.IfElse(assumeTrue, TypeFactsNEUndefined, TypeFactsEQUndefined)) } } @@ -691,7 +691,7 @@ func (c *Checker) narrowTypeByDiscriminantProperty(t *Type, access *ast.Node, op if (operator == ast.KindEqualsEqualsEqualsToken || operator == ast.KindExclamationEqualsEqualsToken) && t.flags&TypeFlagsUnion != 0 { keyPropertyName := c.getKeyPropertyName(t) if keyPropertyName != "" { - if accessedName, ok := c.getAccessedPropertyName(access); ok && keyPropertyName == accessedName { + if accessedName, ok := c.getAccessedPropertyName(access); ok && ast.UnescapeLeadingUnderscores(keyPropertyName) == accessedName { candidate := c.getConstituentTypeForKeyType(t, c.getTypeOfExpression(value)) if candidate != nil { if assumeTrue && operator == ast.KindEqualsEqualsEqualsToken || !assumeTrue && operator == ast.KindExclamationEqualsEqualsToken { @@ -721,7 +721,7 @@ func (c *Checker) narrowTypeByDiscriminant(t *Type, access *ast.Node, narrowType if removeNullable { nonNullType = c.getTypeWithFacts(t, TypeFactsNEUndefinedOrNull) } - propType := c.getTypeOfPropertyOfType(nonNullType, propName) + propType := c.getTypeOfPropertyOfType(nonNullType, ast.EscapeLeadingUnderscores(propName)) if propType == nil { return t } @@ -870,7 +870,7 @@ func (c *Checker) getNarrowedTypeWorker(t *Type, candidate *Type, assumeTrue boo } // We first attempt to filter the current type, narrowing constituents as appropriate and removing // constituents that are unrelated to the candidate. - var keyPropertyName string + var keyPropertyName ast.SymbolNameKey if t.flags&TypeFlagsUnion != 0 { keyPropertyName = c.getKeyPropertyName(t) } @@ -1009,7 +1009,7 @@ func (c *Checker) narrowTypeByInKeyword(f *FlowState, t *Type, nameType *Type, a return t } -func (c *Checker) isTypePresencePossible(t *Type, propName string, assumeTrue bool) bool { +func (c *Checker) isTypePresencePossible(t *Type, propName ast.SymbolNameKey, assumeTrue bool) bool { prop := c.getPropertyOfType(t, propName) if prop != nil { return prop.Flags&ast.SymbolFlagsOptional != 0 || prop.CheckFlags&ast.CheckFlagsPartial != 0 || assumeTrue @@ -1211,7 +1211,7 @@ func (c *Checker) narrowTypeBySwitchOptionalChainContainment(t *Type, data *ast. func (c *Checker) narrowTypeBySwitchOnDiscriminantProperty(t *Type, access *ast.Node, data *ast.FlowSwitchClauseData) *Type { if data.ClauseStart < data.ClauseEnd && t.flags&TypeFlagsUnion != 0 { accessedName, _ := c.getAccessedPropertyName(access) - if accessedName != "" && c.getKeyPropertyName(t) == accessedName { + if accessedName != "" && ast.UnescapeLeadingUnderscores(c.getKeyPropertyName(t)) == accessedName { clauseTypes := c.getSwitchClauseTypes(data.SwitchStatement)[data.ClauseStart:data.ClauseEnd] candidate := c.getUnionType(core.Map(clauseTypes, func(s *Type) *Type { result := c.getConstituentTypeForKeyType(t, s) @@ -1425,7 +1425,7 @@ func (c *Checker) getDiscriminantPropertyAccess(f *FlowState, expr *ast.Node, co if f.declaredType.flags&TypeFlagsUnion != 0 && c.isTypeSubsetOf(computedType, f.declaredType) { t = f.declaredType } - if c.isDiscriminantProperty(t, name) { + if c.isDiscriminantProperty(t, ast.EscapeLeadingUnderscores(name)) { return access } } @@ -1762,7 +1762,7 @@ func (c *Checker) tryGetNameFromEntityNameExpression(node *ast.Node) (string, bo func tryGetNameFromType(t *Type) (string, bool) { switch { case t.flags&TypeFlagsUniqueESSymbol != 0: - return t.AsUniqueESSymbolType().name, true + return t.AsUniqueESSymbolType().name.EscapedText(), true case t.flags&TypeFlagsStringOrNumberLiteral != 0: return evaluator.AnyToString(t.AsLiteralType().value), true } @@ -2084,15 +2084,15 @@ func (c *Checker) getSymbolHasInstanceMethodOfObjectType(t *Type) *Type { return nil } -func (c *Checker) getPropertyNameForKnownSymbolName(symbolName string) string { +func (c *Checker) getPropertyNameForKnownSymbolName(symbolName string) ast.SymbolNameKey { ctorType := c.getGlobalESSymbolConstructorSymbolOrNil() if ctorType != nil { - uniqueType := c.getTypeOfPropertyOfType(c.getTypeOfSymbol(ctorType), symbolName) + uniqueType := c.getTypeOfPropertyOfType(c.getTypeOfSymbol(ctorType), ast.EscapeLeadingUnderscores(symbolName)) if uniqueType != nil && isTypeUsableAsPropertyName(uniqueType) { return getPropertyNameFromType(uniqueType) } } - return ast.InternalSymbolNamePrefix + "@" + symbolName + return ast.InternalSymbolName("@" + symbolName) } // We require the dotted function name in an assertion expression to be comprised of identifiers @@ -2119,7 +2119,7 @@ func (c *Checker) getTypeOfDottedName(node *ast.Node, diagnostic *ast.Diagnostic prop = c.getPropertyOfType(t, binder.GetSymbolNameForPrivateIdentifier(t.symbol, name.Text())) } } else { - prop = c.getPropertyOfType(t, name.Text()) + prop = c.getPropertyOfType(t, ast.EscapeLeadingUnderscores(name.Text())) } if prop != nil { return c.getExplicitTypeOfSymbol(prop, diagnostic) @@ -2436,10 +2436,11 @@ func (c *Checker) getTypePredicateArgument(predicate *TypePredicate, callExpress func (c *Checker) getFlowTypeInConstructor(symbol *ast.Symbol, constructor *ast.Node) *Type { var accessName *ast.Node - if strings.HasPrefix(symbol.Name, ast.InternalSymbolNamePrefix+"#") { - accessName = c.factory.NewPrivateIdentifier(symbol.Name[strings.Index(symbol.Name, "@")+1:]) + name := symbol.Name.EscapedText() + if strings.HasPrefix(name, ast.InternalSymbolNamePrefix+"#") { + accessName = c.factory.NewPrivateIdentifier(name[strings.Index(name, "@")+1:]) } else { - accessName = c.factory.NewIdentifier(symbol.Name) + accessName = c.factory.NewIdentifier(ast.UnescapeLeadingUnderscores(symbol.Name)) } reference := c.factory.NewPropertyAccessExpression(c.factory.NewKeywordExpression(ast.KindThisKeyword), nil, accessName, ast.NodeFlagsNone) reference.Expression().Parent = reference @@ -2458,10 +2459,11 @@ func (c *Checker) getFlowTypeInConstructor(symbol *ast.Symbol, constructor *ast. func (c *Checker) getFlowTypeInStaticBlocks(symbol *ast.Symbol, staticBlocks []*ast.Node) *Type { var accessName *ast.Node - if strings.HasPrefix(symbol.Name, ast.InternalSymbolNamePrefix+"#") { - accessName = c.factory.NewPrivateIdentifier(symbol.Name[strings.Index(symbol.Name, "@")+1:]) + name := symbol.Name.EscapedText() + if strings.HasPrefix(name, ast.InternalSymbolNamePrefix+"#") { + accessName = c.factory.NewPrivateIdentifier(name[strings.Index(name, "@")+1:]) } else { - accessName = c.factory.NewIdentifier(symbol.Name) + accessName = c.factory.NewIdentifier(ast.UnescapeLeadingUnderscores(symbol.Name)) } for _, staticBlock := range staticBlocks { reference := c.factory.NewPropertyAccessExpression(c.factory.NewKeywordExpression(ast.KindThisKeyword), nil, accessName, ast.NodeFlagsNone) diff --git a/internal/checker/inference.go b/internal/checker/inference.go index 67b0c301241..8e8fc6543dd 100644 --- a/internal/checker/inference.go +++ b/internal/checker/inference.go @@ -1233,13 +1233,14 @@ func (c *Checker) createEmptyObjectTypeFromStringLiteral(t *Type) *Type { continue } name := getStringLiteralValue(t) - literalProp := c.newSymbol(ast.SymbolFlagsProperty, name) + symbolName := ast.EscapeLeadingUnderscores(name) + literalProp := c.newSymbol(ast.SymbolFlagsProperty, symbolName) c.valueSymbolLinks.Get(literalProp).resolvedType = c.anyType if t.symbol != nil { literalProp.Declarations = t.symbol.Declarations literalProp.ValueDeclaration = t.symbol.ValueDeclaration } - members[name] = literalProp + members[symbolName] = literalProp } var indexInfos []*IndexInfo if t.flags&TypeFlagsString != 0 { diff --git a/internal/checker/jsx.go b/internal/checker/jsx.go index 696f5255e7f..931eb69e311 100644 --- a/internal/checker/jsx.go +++ b/internal/checker/jsx.go @@ -220,7 +220,7 @@ func (c *Checker) getContextualTypeForJsxAttribute(attribute *ast.Node, contextF if attributesType == nil || IsTypeAny(attributesType) { return nil } - return c.getTypeOfPropertyOfContextualType(attributesType, attribute.Name().Text()) + return c.getTypeOfPropertyOfContextualType(attributesType, ast.EscapeLeadingUnderscores(attribute.Name().Text())) } return c.getContextualType(attribute.Parent, contextFlags) } @@ -306,9 +306,9 @@ func (c *Checker) elaborateJsxComponents(node *ast.Node, source *Type, target *T containingElement := node.Parent.Parent // Containing JSXElement childrenPropName := c.getJsxElementChildrenPropertyName(c.getJsxNamespaceAt(node)) if childrenPropName == ast.InternalSymbolNameMissing { - childrenPropName = "children" + childrenPropName = ast.EscapeLeadingUnderscores("children") } - childrenNameType := c.getStringLiteralType(childrenPropName) + childrenNameType := c.getStringLiteralType(ast.UnescapeLeadingUnderscores(childrenPropName)) childrenTargetType := c.getIndexedAccessType(target, childrenNameType) validChildren := ast.GetSemanticJsxChildren(containingElement.Children().Nodes) if len(validChildren) == 0 { @@ -522,7 +522,7 @@ func (c *Checker) getJSXFragmentType(node *ast.Node) *Type { links.jsxFragmentType = c.errorType return links.jsxFragmentType } - if jsxFactorySymbol.Name == ReactNames.Fragment { + if jsxFactorySymbol.Name == ast.EscapeLeadingUnderscores(ReactNames.Fragment) { links.jsxFragmentType = c.getTypeOfSymbol(jsxFactorySymbol) return links.jsxFragmentType } @@ -753,7 +753,7 @@ func (c *Checker) createJsxAttributesTypeFromAttributesProperty(openingLikeEleme if allAttributesTable != nil { allAttributesTable[attributeSymbol.Name] = attributeSymbol } - if attributeDecl.Name().Text() == jsxChildrenPropertyName { + if ast.EscapeLeadingUnderscores(attributeDecl.Name().Text()) == jsxChildrenPropertyName { explicitlySpecifyChildrenAttribute = true } if contextualType != nil { @@ -828,7 +828,7 @@ func (c *Checker) createJsxAttributesTypeFromAttributesProperty(openingLikeEleme // This is because children element will overwrite the value from attributes. // Note: we will not warn "children" attribute overwritten if "children" attribute is specified in object spread. if explicitlySpecifyChildrenAttribute { - c.error(attributeParent, diagnostics.X_0_are_specified_twice_The_attribute_named_0_will_be_overwritten, jsxChildrenPropertyName) + c.error(attributeParent, diagnostics.X_0_are_specified_twice_The_attribute_named_0_will_be_overwritten, ast.UnescapeLeadingUnderscores(jsxChildrenPropertyName)) } var childrenContextualType *Type if ast.IsJsxOpeningElement(openingLikeElement) { @@ -848,7 +848,7 @@ func (c *Checker) createJsxAttributesTypeFromAttributesProperty(openingLikeEleme links.resolvedType = c.createArrayType(c.getUnionType(childTypes)) } // Fake up a property declaration for the children - childrenPropSymbol.ValueDeclaration = c.factory.NewPropertySignatureDeclaration(nil, c.factory.NewIdentifier(jsxChildrenPropertyName), nil /*postfixToken*/, nil /*type*/, nil /*initializer*/) + childrenPropSymbol.ValueDeclaration = c.factory.NewPropertySignatureDeclaration(nil, c.factory.NewIdentifier(ast.UnescapeLeadingUnderscores(jsxChildrenPropertyName)), nil /*postfixToken*/, nil /*type*/, nil /*initializer*/) childrenPropSymbol.ValueDeclaration.Parent = attributeParent childrenPropSymbol.ValueDeclaration.AsPropertySignatureDeclaration().Symbol = childrenPropSymbol childPropMap := make(ast.SymbolTable) @@ -954,10 +954,10 @@ func (c *Checker) getJsxPropsTypeFromClassType(sig *Signature, context *ast.Node case "": attributesType = c.getReturnTypeOfSignature(sig) default: - attributesType = c.getJsxPropsTypeForSignatureFromMember(sig, forcedLookupLocation) + attributesType = c.getJsxPropsTypeForSignatureFromMember(sig, ast.UnescapeLeadingUnderscores(forcedLookupLocation)) if attributesType == nil && len(context.Attributes().Properties()) != 0 { // There is no property named 'props' on this instance type - c.error(context, diagnostics.JSX_element_class_does_not_support_attributes_because_it_does_not_have_a_0_property, forcedLookupLocation) + c.error(context, diagnostics.JSX_element_class_does_not_support_attributes_because_it_does_not_have_a_0_property, ast.UnescapeLeadingUnderscores(forcedLookupLocation)) } } if attributesType == nil { @@ -1004,7 +1004,7 @@ func (c *Checker) getJsxPropsTypeForSignatureFromMember(sig *Signature, forcedLo if IsTypeAny(instance) { return instance } - propType := c.getTypeOfPropertyOfType(instance, forcedLookupLocation) + propType := c.getTypeOfPropertyOfType(instance, ast.EscapeLeadingUnderscores(forcedLookupLocation)) if propType == nil { return nil } @@ -1017,7 +1017,7 @@ func (c *Checker) getJsxPropsTypeForSignatureFromMember(sig *Signature, forcedLo if IsTypeAny(instanceType) { return instanceType } - return c.getTypeOfPropertyOfType(instanceType, forcedLookupLocation) + return c.getTypeOfPropertyOfType(instanceType, ast.EscapeLeadingUnderscores(forcedLookupLocation)) } func (c *Checker) getJsxManagedAttributesFromLocatedAttributes(context *ast.Node, ns *ast.Symbol, attributesType *Type) *Type { @@ -1075,14 +1075,14 @@ func (c *Checker) getJsxElementTypeSymbol(jsxNamespace *ast.Symbol) *ast.Symbol // or "" if it has 0 properties (which means every // // non-intrinsic elements' attributes type is the element instance type) -func (c *Checker) getJsxElementPropertiesName(jsxNamespace *ast.Symbol) string { +func (c *Checker) getJsxElementPropertiesName(jsxNamespace *ast.Symbol) ast.SymbolNameKey { return c.getNameFromJsxElementAttributesContainer(JsxNames.ElementAttributesPropertyNameContainer, jsxNamespace) } -func (c *Checker) getJsxElementChildrenPropertyName(jsxNamespace *ast.Symbol) string { +func (c *Checker) getJsxElementChildrenPropertyName(jsxNamespace *ast.Symbol) ast.SymbolNameKey { if c.compilerOptions.Jsx == core.JsxEmitReactJSX || c.compilerOptions.Jsx == core.JsxEmitReactJSXDev { // In these JsxEmit modes the children property is fixed to 'children' - return "children" + return ast.EscapeLeadingUnderscores("children") } return c.getNameFromJsxElementAttributesContainer(JsxNames.ElementChildrenAttributeNameContainer, jsxNamespace) } @@ -1093,7 +1093,7 @@ func (c *Checker) getJsxElementChildrenPropertyName(jsxNamespace *ast.Symbol) st // @param nameOfAttribPropContainer a string of value JsxNames.ElementAttributesPropertyNameContainer or JsxNames.ElementChildrenAttributeNameContainer // // if other string is given or the container doesn't exist, return undefined. -func (c *Checker) getNameFromJsxElementAttributesContainer(nameOfAttribPropContainer string, jsxNamespace *ast.Symbol) string { +func (c *Checker) getNameFromJsxElementAttributesContainer(nameOfAttribPropContainer string, jsxNamespace *ast.Symbol) ast.SymbolNameKey { // JSX.ElementAttributesProperty | JSX.ElementChildrenAttribute [symbol] if jsxNamespace != nil { jsxElementAttribPropInterfaceSym := c.getSymbol(jsxNamespace.Exports, nameOfAttribPropContainer, ast.SymbolFlagsType) @@ -1145,7 +1145,7 @@ func (c *Checker) getIntrinsicAttributesTypeFromStringLiteralType(t *Type, locat intrinsicElementsType := c.getJsxType(JsxNames.IntrinsicElements, location) if !c.isErrorType(intrinsicElementsType) { stringLiteralTypeName := getStringLiteralValue(t) - intrinsicProp := c.getPropertyOfType(intrinsicElementsType, stringLiteralTypeName) + intrinsicProp := c.getPropertyOfType(intrinsicElementsType, ast.EscapeLeadingUnderscores(stringLiteralTypeName)) if intrinsicProp != nil { return c.getTypeOfSymbol(intrinsicProp) } @@ -1202,7 +1202,7 @@ func (c *Checker) getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node *ast. return links.resolvedJsxElementAttributesType } if links.jsxFlags&JsxFlagsIntrinsicIndexedElement != 0 { - indexInfo := c.getApplicableIndexInfoForName(c.getJsxType(JsxNames.IntrinsicElements, node), node.TagName().Text()) + indexInfo := c.getApplicableIndexInfoForName(c.getJsxType(JsxNames.IntrinsicElements, node), ast.EscapeLeadingUnderscores(node.TagName().Text())) if indexInfo != nil { links.resolvedJsxElementAttributesType = indexInfo.valueType return links.resolvedJsxElementAttributesType @@ -1229,7 +1229,7 @@ func (c *Checker) getIntrinsicTagSymbol(node *ast.Node) *ast.Symbol { panic("Invalid tag name") } propName := tagName.Text() - intrinsicProp := c.getPropertyOfType(intrinsicElementsType, propName) + intrinsicProp := c.getPropertyOfType(intrinsicElementsType, ast.EscapeLeadingUnderscores(propName)) if intrinsicProp != nil { c.jsxElementLinks.Get(node).jsxFlags |= JsxFlagsIntrinsicNamedElement links.resolvedSymbol = intrinsicProp diff --git a/internal/checker/nodebuilder_hover.go b/internal/checker/nodebuilder_hover.go index eaa83edc2b2..a6306deec04 100644 --- a/internal/checker/nodebuilder_hover.go +++ b/internal/checker/nodebuilder_hover.go @@ -60,7 +60,7 @@ func (b *NodeBuilderImpl) expandEnumDecl(symbol *ast.Symbol) *ast.Node { b.ctx.expansionTruncated = true members = append(members, b.f.NewEnumMember(b.f.NewStringLiteral(fmt.Sprintf(" ... %d more ... ", len(memberProps)-i-1), 0), nil)) last := memberProps[len(memberProps)-1] - members = append(members, b.f.NewEnumMember(b.f.NewIdentifier(last.Name), b.enumMemberInitializer(last))) + members = append(members, b.f.NewEnumMember(b.f.NewIdentifier(ast.UnescapeLeadingUnderscores(last.Name)), b.enumMemberInitializer(last))) break } memberDecl := core.Find(p.Declarations, ast.IsEnumMember) @@ -74,7 +74,7 @@ func (b *NodeBuilderImpl) expandEnumDecl(symbol *ast.Symbol) *ast.Node { if initializer != nil { b.ctx.approximateLength += 5 // " = " + value estimate } - members = append(members, b.f.NewEnumMember(b.f.NewIdentifier(p.Name), initializer)) + members = append(members, b.f.NewEnumMember(b.f.NewIdentifier(ast.UnescapeLeadingUnderscores(p.Name)), initializer)) } constModifier := ast.ModifierFlagsNone @@ -417,7 +417,7 @@ func (b *NodeBuilderImpl) expandModuleDecl(symbol *ast.Symbol) *ast.Node { if !b.isNamespaceMember(sym) { continue } - if !scanner.IsIdentifierText(sym.Name, core.LanguageVariantStandard) { + if !scanner.IsIdentifierText(ast.UnescapeLeadingUnderscores(sym.Name), core.LanguageVariantStandard) { continue } members = append(members, sym) @@ -459,21 +459,21 @@ func (b *NodeBuilderImpl) expandModuleDecl(symbol *ast.Symbol) *ast.Node { b.ctx.approximateLength += len(target.Name) + 5 localStmt := b.f.NewVariableStatement(nil, b.f.NewVariableDeclarationList(b.f.NewNodeList([]*ast.Node{ - b.f.NewVariableDeclaration(b.f.NewIdentifier(target.Name), nil, b.serializeTypeForDeclaration(nil, localType, target, true), nil), + b.f.NewVariableDeclaration(b.f.NewIdentifier(ast.UnescapeLeadingUnderscores(target.Name)), nil, b.serializeTypeForDeclaration(nil, localType, target, true), nil), }), ast.NodeFlagsLet)) bodyStmts = append(bodyStmts, hoverStatement{node: localStmt, isLocal: true}) } } - targetName := target.Name + targetName := ast.UnescapeLeadingUnderscores(target.Name) b.ctx.approximateLength += 16 + len(m.Name) var propertyName *ast.Node - if m.Name != targetName { + if m.Name != target.Name { propertyName = b.f.NewIdentifier(targetName) } stmt := b.f.NewExportDeclaration( nil, false, b.f.NewNamedExports(b.f.NewNodeList([]*ast.Node{ - b.f.NewExportSpecifier(false, propertyName, b.f.NewIdentifier(m.Name)), + b.f.NewExportSpecifier(false, propertyName, b.f.NewIdentifier(ast.UnescapeLeadingUnderscores(m.Name))), })), nil, nil, ) @@ -491,7 +491,7 @@ func (b *NodeBuilderImpl) expandModuleDecl(symbol *ast.Symbol) *ast.Node { for _, sig := range sigs { b.ctx.approximateLength++ decl := b.signatureToSignatureDeclarationHelper(sig, ast.KindFunctionDeclaration, &SignatureToSignatureDeclarationOptions{ - name: b.f.NewIdentifier(m.Name), + name: b.f.NewIdentifier(ast.UnescapeLeadingUnderscores(m.Name)), }) bodyStmts = append(bodyStmts, hoverStatement{node: decl}) } @@ -499,13 +499,13 @@ func (b *NodeBuilderImpl) expandModuleDecl(symbol *ast.Symbol) *ast.Node { merged := b.ch.getMergedSymbol(resolved) hasModuleExports := merged.Flags&(ast.SymbolFlagsValueModule|ast.SymbolFlagsNamespaceModule) != 0 && merged.Exports != nil && len(merged.Exports) != 0 if !hasModuleExports { - bodyStmts = append(bodyStmts, hoverStatement{node: b.f.NewModuleDeclaration(nil, ast.KindNamespaceKeyword, b.f.NewIdentifier(m.Name), b.f.NewModuleBlock(b.f.NewNodeList(nil)))}) + bodyStmts = append(bodyStmts, hoverStatement{node: b.f.NewModuleDeclaration(nil, ast.KindNamespaceKeyword, b.f.NewIdentifier(ast.UnescapeLeadingUnderscores(m.Name)), b.f.NewModuleBlock(b.f.NewNodeList(nil)))}) } continue } // Handle remaining member kinds (type alias, enum, class, interface, namespace, variable) - if node := b.serializeNamespaceMember(resolved, m.Name); node != nil { + if node := b.serializeNamespaceMember(resolved, ast.UnescapeLeadingUnderscores(m.Name)); node != nil { bodyStmts = append(bodyStmts, hoverStatement{node: node}) } } @@ -565,12 +565,12 @@ func (b *NodeBuilderImpl) filterInheritedProperties(t *Type, baseTypes []*Type, return properties } // Build a lookup from property name to symbol for parent-identity comparison. - propsByName := make(map[string]*ast.Symbol, len(properties)) + propsByName := make(map[ast.SymbolNameKey]*ast.Symbol, len(properties)) for _, p := range properties { propsByName[p.Name] = p } // Collect names of properties inherited unchanged from base types. - var inherited collections.Set[string] + var inherited collections.Set[ast.SymbolNameKey] for _, base := range baseTypes { baseWithThis := b.ch.getTypeWithThisArgument(base, b.ch.getTargetType(t).AsInterfaceType().thisType, false) for _, prop := range b.ch.getPropertiesOfType(baseWithThis) { diff --git a/internal/checker/nodebuilderimpl.go b/internal/checker/nodebuilderimpl.go index 2eda08fd60c..c77f7117faf 100644 --- a/internal/checker/nodebuilderimpl.go +++ b/internal/checker/nodebuilderimpl.go @@ -634,7 +634,7 @@ func (b *NodeBuilderImpl) createEntityNameFromSymbolChain(chain []*ast.Symbol, i // TODO: Audit usages of symbolToEntityNameNode - they should probably all be symbolToName func (b *NodeBuilderImpl) symbolToEntityNameNode(symbol *ast.Symbol) *ast.EntityName { - identifier := b.newIdentifier(symbol.Name, symbol) + identifier := b.newIdentifier(ast.UnescapeLeadingUnderscores(symbol.Name), symbol) if symbol.Parent != nil { return b.f.NewQualifiedName(b.symbolToEntityNameNode(symbol.Parent), identifier) } @@ -706,7 +706,7 @@ func (b *NodeBuilderImpl) symbolToTypeNode(symbol *ast.Symbol, mask ast.SymbolFl // If ultimately we can only name the symbol with a reference that dives into a `node_modules` folder, we should error // since declaration files with these kinds of references are liable to fail when published :( b.ctx.encounteredError = true - b.ctx.tracker.ReportLikelyUnsafeImportRequiredError(oldSpecifier, symbol.Name) + b.ctx.tracker.ReportLikelyUnsafeImportRequiredError(oldSpecifier, ast.UnescapeLeadingUnderscores(symbol.Name)) } } @@ -779,12 +779,12 @@ func (b *NodeBuilderImpl) createAccessFromSymbolChain(chain []*ast.Symbol, index // avoid exhaustive iteration in the common case res, ok := exports[symbol.Name] if symbol.Name != ast.InternalSymbolNameExportEquals && !isLateBoundName(symbol.Name) && ok && res != nil && b.ch.getSymbolIfSameReference(res, symbol) != nil { - symbolName = symbol.Name + symbolName = ast.UnescapeLeadingUnderscores(symbol.Name) } else { results := make(map[*ast.Symbol]string, 1) for name, ex := range exports { if b.ch.getSymbolIfSameReference(ex, symbol) != nil && !isLateBoundName(name) && name != ast.InternalSymbolNameExportEquals { - results[ex] = name + results[ex] = ast.UnescapeLeadingUnderscores(name) // break // must collect all results and sort them - exports are randomly iterated } } @@ -1021,7 +1021,7 @@ func (b *NodeBuilderImpl) getNameOfSymbolAsWritten(symbol *ast.Symbol) string { if len(name) > 0 { return name } - return ast.EscapeInternalSymbolName(symbol.Name) + return ast.UnescapeLeadingUnderscores(symbol.Name) } // The full set of type parameters for a generic class or interface type consists of its outer type parameters plus @@ -1258,13 +1258,13 @@ func (b *NodeBuilderImpl) getSpecifierForModuleSymbol(symbol *ast.Symbol, overri } if file == nil { - if ast.IsAmbientModuleSymbolName(symbol.Name) { - return stringutil.StripQuotes(symbol.Name) + if ast.IsAmbientModuleSymbolName(ast.UnescapeLeadingUnderscores(symbol.Name)) { + return stringutil.StripQuotes(ast.UnescapeLeadingUnderscores(symbol.Name)) } } if b.ctx.enclosingFile == nil { - if ast.IsAmbientModuleSymbolName(symbol.Name) { - return stringutil.StripQuotes(symbol.Name) + if ast.IsAmbientModuleSymbolName(ast.UnescapeLeadingUnderscores(symbol.Name)) { + return stringutil.StripQuotes(ast.UnescapeLeadingUnderscores(symbol.Name)) } return ast.GetSourceFileOfModule(symbol).FileName() } @@ -1690,7 +1690,7 @@ func (b *NodeBuilderImpl) symbolToParameterDeclaration(parameterSymbol *ast.Symb func (b *NodeBuilderImpl) parameterToParameterDeclarationName(parameterSymbol *ast.Symbol, parameterDeclaration *ast.Node) *ast.Node { if parameterDeclaration == nil || parameterDeclaration.Name() == nil { - return b.newIdentifier(parameterSymbol.Name, parameterSymbol) + return b.newIdentifier(ast.UnescapeLeadingUnderscores(parameterSymbol.Name), parameterSymbol) } name := parameterDeclaration.Name() @@ -1974,7 +1974,7 @@ func (c *Checker) getExpandedParameters(sig *Signature, skipUnionExpanding bool) case flags&ElementFlagsOptional != 0: checkFlags = ast.CheckFlagsOptionalParameter } - symbol := c.newSymbolEx(ast.SymbolFlagsFunctionScopedVariable, name, checkFlags) + symbol := c.newSymbolEx(ast.SymbolFlagsFunctionScopedVariable, ast.EscapeLeadingUnderscores(name), checkFlags) links := c.valueSymbolLinks.Get(symbol) if flags&ElementFlagsRest != 0 { links.resolvedType = c.createArrayType(t) @@ -2426,13 +2426,15 @@ func (b *NodeBuilderImpl) getPropertyNameNodeForSymbol(symbol *ast.Symbol) *ast. return fromNameType } - name := symbol.Name + name := symbol.Name.EscapedText() const privateNamePrefix = ast.InternalSymbolNamePrefix + "#" if strings.HasPrefix(name, privateNamePrefix) { // symbol IDs are unstable - replace #nnn# with #private# name = name[len(privateNamePrefix):] name = strings.TrimLeftFunc(name, stringutil.IsDigit) name = "__#private" + name + } else { + name = ast.UnescapeLeadingUnderscores(symbol.Name) } return b.createPropertyNameNodeForIdentifierOrLiteral(name, singleQuote, stringNamed, isMethod, symbol) @@ -2649,7 +2651,7 @@ func (b *NodeBuilderImpl) createTypeNodesFromResolvedType(resolvedType *Structur continue } if getDeclarationModifierFlagsFromSymbol(propertySymbol)&(ast.ModifierFlagsPrivate|ast.ModifierFlagsProtected) != 0 { - b.ctx.tracker.ReportPrivateInBaseOfClassExpression(propertySymbol.Name) + b.ctx.tracker.ReportPrivateInBaseOfClassExpression(ast.UnescapeLeadingUnderscores(propertySymbol.Name)) } if IsPrivateIdentifierSymbol(propertySymbol) { b.ctx.tracker.ReportPrivateInBaseOfClassExpression(ast.SymbolName(propertySymbol)) diff --git a/internal/checker/nodebuilderscopes.go b/internal/checker/nodebuilderscopes.go index 06a8ec51b24..08181efcbb9 100644 --- a/internal/checker/nodebuilderscopes.go +++ b/internal/checker/nodebuilderscopes.go @@ -33,7 +33,7 @@ func cloneNodeBuilderContext(context *NodeBuilderContext) func() { } type localsRecord struct { - name string + name ast.SymbolNameKey oldSymbol *ast.Symbol } @@ -121,19 +121,20 @@ func (b *NodeBuilderImpl) enterNewScope(declaration *ast.Node, expandedParams [] if locals == nil { locals = make(ast.SymbolTable) } - newLocals := []string{} + newLocals := []ast.SymbolNameKey{} oldLocals := []localsRecord{} addAll(func(name string, symbol *ast.Symbol) { + symbolName := ast.EscapeLeadingUnderscores(name) // Add cleanup information only if we don't own the fake scope if existingFakeScope != nil { - oldSymbol, ok := locals[name] + oldSymbol, ok := locals[symbolName] if !ok || oldSymbol == nil { - newLocals = append(newLocals, name) + newLocals = append(newLocals, symbolName) } else { - oldLocals = append(oldLocals, localsRecord{name, oldSymbol}) + oldLocals = append(oldLocals, localsRecord{symbolName, oldSymbol}) } } - locals[name] = symbol + locals[symbolName] = symbol }) if existingFakeScope == nil { @@ -175,7 +176,7 @@ func (b *NodeBuilderImpl) enterNewScope(declaration *ast.Node, expandedParams [] if originalParameters != nil && originalParam != param { // Can't reference the expanded parameter name, just the original, unless we've expanded the param list for some reason if originalParam != nil { - add(originalParam.Name, originalParam) + add(ast.UnescapeLeadingUnderscores(originalParam.Name), originalParam) } } else if !core.Some(param.Declarations, func(d *ast.Node) bool { var bindElement func(e *ast.BindingElement) @@ -202,7 +203,7 @@ func (b *NodeBuilderImpl) enterNewScope(declaration *ast.Node, expandedParams [] } symbol := b.ch.getSymbolOfDeclaration(e.AsNode()) if symbol != nil { // omitted expressions are now parsed as nameless binding patterns and also have no symbol - add(symbol.Name, symbol) + add(ast.UnescapeLeadingUnderscores(symbol.Name), symbol) } } bindElement = bindElementWorker @@ -214,7 +215,7 @@ func (b *NodeBuilderImpl) enterNewScope(declaration *ast.Node, expandedParams [] } return false }) { - add(param.Name, param) + add(ast.UnescapeLeadingUnderscores(param.Name), param) } } }) diff --git a/internal/checker/relater.go b/internal/checker/relater.go index e649e25b10b..fd8fb25bc39 100644 --- a/internal/checker/relater.go +++ b/internal/checker/relater.go @@ -533,7 +533,7 @@ func (c *Checker) elaborateArrayLiteral(node *ast.Node, source *Type, target *Ty } reportedError := false for i, element := range node.Elements() { - if ast.IsOmittedExpression(element) || c.isTupleLikeType(target) && c.getPropertyOfType(target, jsnum.Number(i).String()) == nil { + if ast.IsOmittedExpression(element) || c.isTupleLikeType(target) && c.getPropertyOfType(target, ast.EscapeLeadingUnderscores(jsnum.Number(i).String())) == nil { continue } nameType := c.getNumberLiteralType(jsnum.Number(i)) @@ -585,7 +585,7 @@ func (c *Checker) elaborateElement(source *Type, target *Type, relation *Relatio return false } diagnostic := diags[0] - var propertyName string + var propertyName ast.SymbolNameKey var targetProp *ast.Symbol if isTypeUsableAsPropertyName(nameType) { propertyName = getPropertyNameFromType(nameType) @@ -607,10 +607,10 @@ func (c *Checker) elaborateElement(source *Type, target *Type, relation *Relatio targetNode = target.symbol.Declarations[0] } if propertyName == "" || nameType.flags&TypeFlagsUniqueESSymbol != 0 { - propertyName = c.TypeToString(nameType) + propertyName = ast.EscapeLeadingUnderscores(c.TypeToString(nameType)) } if !c.program.IsSourceFileDefaultLibrary(ast.GetSourceFileOfNode(targetNode).Path()) { - diagnostic.AddRelatedInfo(createDiagnosticForNode(targetNode, diagnostics.The_expected_type_comes_from_property_0_which_is_declared_here_on_type_1, propertyName, c.TypeToString(target))) + diagnostic.AddRelatedInfo(createDiagnosticForNode(targetNode, diagnostics.The_expected_type_comes_from_property_0_which_is_declared_here_on_type_1, ast.UnescapeLeadingUnderscores(propertyName), c.TypeToString(target))) } } c.reportDiagnostic(diagnostic, diagnosticOutput) @@ -716,7 +716,7 @@ func (c *Checker) hasCommonProperties(source *Type, target *Type, isComparingJsx * @param name a property name to search * @param isComparingJsxAttributes a boolean flag indicating whether we are searching in JsxAttributesType */ -func (c *Checker) isKnownProperty(targetType *Type, name string, isComparingJsxAttributes bool) bool { +func (c *Checker) isKnownProperty(targetType *Type, name ast.SymbolNameKey, isComparingJsxAttributes bool) bool { if targetType.flags&TypeFlagsObject != 0 { // For backwards compatibility a symbol-named property is satisfied by a string index signature. This // is incorrect and inconsistent with element access expressions, where it is an error, so eventually @@ -724,7 +724,7 @@ func (c *Checker) isKnownProperty(targetType *Type, name string, isComparingJsxA if c.getPropertyOfObjectType(targetType, name) != nil || c.getApplicableIndexInfoForName(targetType, name) != nil || isLateBoundName(name) && c.getIndexInfoOfType(targetType, c.stringType) != nil || - isComparingJsxAttributes && isHyphenatedJsxName(name) { + isComparingJsxAttributes && isHyphenatedJsxName(ast.UnescapeLeadingUnderscores(name)) { // For JSXAttributes, if the attribute has a hyphenated name, consider that the attribute to be known. return true } @@ -1019,7 +1019,7 @@ func excludeProperties(properties []*ast.Symbol, excludedProperties collections. var reduced []*ast.Symbol var excluded bool for i, prop := range properties { - if !excludedProperties.Has(prop.Name) { + if !excludedProperties.Has(ast.UnescapeLeadingUnderscores(prop.Name)) { if excluded { reduced = append(reduced, prop) } @@ -1045,7 +1045,7 @@ func (d *TypeDiscriminator) len() int { } func (d *TypeDiscriminator) name(index int) string { - return d.props[index].Name + return ast.UnescapeLeadingUnderscores(d.props[index].Name) } func (d *TypeDiscriminator) matches(index int, t *Type) bool { @@ -1084,7 +1084,7 @@ func (c *Checker) findDiscriminantProperties(sourceProperties []*ast.Symbol, tar return result } -func (c *Checker) isDiscriminantProperty(t *Type, name string) bool { +func (c *Checker) isDiscriminantProperty(t *Type, name ast.SymbolNameKey) bool { if t != nil && t.flags&TypeFlagsUnion != 0 { prop := c.getUnionOrIntersectionProperty(t, name, false /*skipObjectFunctionPropertyAugment*/) if prop != nil && prop.CheckFlags&ast.CheckFlagsSyntheticProperty != 0 { @@ -1115,7 +1115,7 @@ func (c *Checker) getMatchingUnionConstituentForType(unionType *Type, t *Type) * // Return the name of a discriminant property for which it was possible and feasible to construct a map of // constituent types keyed by the literal types of the property by that name in each constituent type. Return // an empty string if no such discriminant property exists. -func (c *Checker) getKeyPropertyName(t *Type) string { +func (c *Checker) getKeyPropertyName(t *Type) ast.SymbolNameKey { u := t.AsUnionType() if u.keyPropertyName == "" { u.keyPropertyName, u.constituentMap = c.computeKeyPropertyNameAndMap(t) @@ -1136,7 +1136,7 @@ func (c *Checker) getConstituentTypeForKeyType(t *Type, keyType *Type) *Type { return nil } -func (c *Checker) computeKeyPropertyNameAndMap(t *Type) (string, map[*Type]*Type) { +func (c *Checker) computeKeyPropertyNameAndMap(t *Type) (ast.SymbolNameKey, map[*Type]*Type) { types := t.Types() if len(types) < 10 || t.objectFlags&ObjectFlagsPrimitiveUnion != 0 || core.CountWhere(types, isObjectOrInstantiableNonPrimitive) < 10 { return ast.InternalSymbolNameMissing, nil @@ -1156,7 +1156,7 @@ func isObjectOrInstantiableNonPrimitive(t *Type) bool { return t.flags&(TypeFlagsObject|TypeFlagsInstantiableNonPrimitive) != 0 } -func (c *Checker) getKeyPropertyCandidateName(types []*Type) string { +func (c *Checker) getKeyPropertyCandidateName(types []*Type) ast.SymbolNameKey { for _, t := range types { if t.flags&(TypeFlagsObject|TypeFlagsInstantiableNonPrimitive) != 0 { for _, p := range c.getPropertiesOfType(t) { @@ -1173,7 +1173,7 @@ func (c *Checker) getKeyPropertyCandidateName(types []*Type) string { // types of the property by that name in each constituent type. No map is returned if some key property // has a non-literal type or if less than 10 or less than 50% of the constituents have a unique key. // Entries with duplicate keys have unknownType as the value. -func (c *Checker) mapTypesByKeyProperty(types []*Type, keyPropertyName string) map[*Type]*Type { +func (c *Checker) mapTypesByKeyProperty(types []*Type, keyPropertyName ast.SymbolNameKey) map[*Type]*Type { typesByKey := make(map[*Type]*Type) count := 0 for _, t := range types { @@ -1929,7 +1929,7 @@ func (c *Checker) isInstantiatedGenericParameter(signature *Signature, pos int) func (c *Checker) getParameterNameAtPosition(signature *Signature, pos int) string { paramCount := len(signature.parameters) - core.IfElse(signatureHasRestParameter(signature), 1, 0) if pos < paramCount { - return signature.parameters[pos].Name + return ast.UnescapeLeadingUnderscores(signature.parameters[pos].Name) } restParameter := signature.parameters[paramCount] restType := c.getTypeOfSymbol(restParameter) @@ -1937,7 +1937,7 @@ func (c *Checker) getParameterNameAtPosition(signature *Signature, pos int) stri index := pos - paramCount return c.getTupleElementLabel(restType.TargetTupleType().elementInfos[index], restParameter, index) } - return restParameter.Name + return ast.UnescapeLeadingUnderscores(restParameter.Name) } func (c *Checker) getTupleElementLabel(elementInfo TupleElementInfo, restSymbol *ast.Symbol, index int) string { @@ -1949,7 +1949,7 @@ func (c *Checker) getTupleElementLabel(elementInfo TupleElementInfo, restSymbol } var rootName string if restSymbol != nil { - rootName = restSymbol.Name + rootName = ast.UnescapeLeadingUnderscores(restSymbol.Name) } else { rootName = "arg" } @@ -2093,7 +2093,7 @@ func (c *Checker) createTypePredicateFromTypePredicateNode(node *ast.Node, signa } kind := core.IfElse(predicateNode.AssertsModifier != nil, TypePredicateKindAssertsIdentifier, TypePredicateKindIdentifier) name := predicateNode.ParameterName.Text() - index := core.FindIndex(signature.parameters, func(p *ast.Symbol) bool { return p.Name == name }) + index := core.FindIndex(signature.parameters, func(p *ast.Symbol) bool { return p.Name == ast.EscapeLeadingUnderscores(name) }) return c.newTypePredicate(kind, name, int32(index), t) } @@ -2793,7 +2793,7 @@ func (r *Relater) hasExcessProperties(source *Type, target *Type, reportErrors b return false } -func (c *Checker) getTypeOfPropertyInTypes(types []*Type, name string) *Type { +func (c *Checker) getTypeOfPropertyInTypes(types []*Type, name ast.SymbolNameKey) *Type { var propTypes []*Type for _, t := range types { propTypes = append(propTypes, c.getTypeOfPropertyInType(t, name)) @@ -2801,7 +2801,7 @@ func (c *Checker) getTypeOfPropertyInTypes(types []*Type, name string) *Type { return c.getUnionType(propTypes) } -func (c *Checker) getTypeOfPropertyInType(t *Type, name string) *Type { +func (c *Checker) getTypeOfPropertyInType(t *Type, name ast.SymbolNameKey) *Type { t = c.getApparentType(t) var prop *ast.Symbol if t.flags&TypeFlagsUnionOrIntersection != 0 { @@ -2824,7 +2824,7 @@ func shouldCheckAsExcessProperty(prop *ast.Symbol, container *ast.Symbol) bool { } func isIgnoredJsxProperty(source *Type, sourceProp *ast.Symbol) bool { - return source.objectFlags&ObjectFlagsJsxAttributes != 0 && isHyphenatedJsxName(sourceProp.Name) + return source.objectFlags&ObjectFlagsJsxAttributes != 0 && isHyphenatedJsxName(ast.UnescapeLeadingUnderscores(sourceProp.Name)) } func (c *Checker) isTypeSubsetOf(source *Type, target *Type) bool { @@ -4025,7 +4025,7 @@ func (r *Relater) typeRelatedToDiscriminatedType(source *Type, target *Type) Ter for i, sourceProperty := range sourcePropertiesFiltered { sourcePropertyType := r.c.getNonMissingTypeOfSymbol(sourceProperty) sourceDiscriminantTypes[i] = sourcePropertyType.Distributed() - excludedProperties.Add(sourceProperty.Name) + excludedProperties.Add(ast.UnescapeLeadingUnderscores(sourceProperty.Name)) } // Build the cartesian product discriminantCombinations := make([][]*Type, numCombinations) @@ -4246,7 +4246,8 @@ func (r *Relater) propertiesRelatedTo(source *Type, target *Type, reportErrors b numericNamesOnly := isTupleType(source) && isTupleType(target) for _, targetProp := range excludeProperties(properties, excludedProperties) { name := targetProp.Name - if targetProp.Flags&ast.SymbolFlagsPrototype == 0 && (!numericNamesOnly || isNumericLiteralName(name) || name == "length") && (!optionalsOnly || targetProp.Flags&ast.SymbolFlagsOptional != 0) { + unescapedName := ast.UnescapeLeadingUnderscores(name) + if targetProp.Flags&ast.SymbolFlagsPrototype == 0 && (!numericNamesOnly || isNumericLiteralName(unescapedName) || unescapedName == "length") && (!optionalsOnly || targetProp.Flags&ast.SymbolFlagsOptional != 0) { sourceProp := r.c.getPropertyOfType(source, name) if sourceProp != nil && sourceProp != targetProp { related := r.propertyRelatedTo(source, target, sourceProp, targetProp, r.c.getNonMissingTypeOfSymbol, reportErrors, intersectionState, r.relation == r.c.comparableRelation) diff --git a/internal/checker/services.go b/internal/checker/services.go index 12b9d407922..acee6974e6b 100644 --- a/internal/checker/services.go +++ b/internal/checker/services.go @@ -125,7 +125,7 @@ func (c *Checker) GetExportsOfModule(symbol *ast.Symbol) []*ast.Symbol { func (c *Checker) ForEachExportAndPropertyOfModule(moduleSymbol *ast.Symbol, cb func(*ast.Symbol, string)) { for key, exportedSymbol := range c.getExportsOfModule(moduleSymbol) { if !isReservedMemberName(key) { - cb(exportedSymbol, key) + cb(exportedSymbol, ast.UnescapeLeadingUnderscores(key)) } } @@ -146,7 +146,7 @@ func (c *Checker) ForEachExportAndPropertyOfModule(moduleSymbol *ast.Symbol, cb } for name, symbol := range c.resolveStructuredTypeMembers(reducedType).members { if c.isNamedMember(symbol, name) { - cb(symbol, name) + cb(symbol, ast.UnescapeLeadingUnderscores(name)) } } } @@ -173,7 +173,7 @@ func (c *Checker) isValidPropertyAccessWithType(node *ast.Node, isSuper bool, pr return true } - prop := c.getPropertyOfType(t, propertyName) + prop := c.getPropertyOfType(t, ast.EscapeLeadingUnderscores(propertyName)) return prop != nil && c.isPropertyAccessible(node, isSuper, false /*isWrite*/, t, prop) } @@ -295,14 +295,14 @@ func (c *Checker) TryGetMemberInModuleExportsAndProperties(memberName string, mo t := c.getTypeOfSymbol(exportEquals) if c.shouldTreatPropertiesOfExternalModuleAsExports(t) { - return c.getPropertyOfType(t, memberName) + return c.getPropertyOfType(t, ast.EscapeLeadingUnderscores(memberName)) } return nil } func (c *Checker) TryGetMemberInModuleExports(memberName string, moduleSymbol *ast.Symbol) *ast.Symbol { symbolTable := c.getExportsOfModule(moduleSymbol) - return symbolTable[memberName] + return symbolTable[ast.EscapeLeadingUnderscores(memberName)] } func (c *Checker) shouldTreatPropertiesOfExternalModuleAsExports(resolvedExternalModuleType *Type) bool { @@ -577,7 +577,7 @@ func (c *Checker) GetReferencesToSymbolInFile( sourceFile *ast.SourceFile, symbol *ast.Symbol, ) []*ast.Node { - identifierText := symbol.Name + identifierText := ast.UnescapeLeadingUnderscores(symbol.Name) var result []*ast.Node for _, token := range getPossibleSymbolReferenceNodes(sourceFile, identifierText, sourceFile.AsNode()) { if !ast.IsIdentifier(token) { @@ -814,7 +814,7 @@ func (c *Checker) IsTypeInvalidDueToUnionDiscriminant(contextualType *Type, obj nameType = c.getLiteralTypeFromPropertyName(propertyName) } } - var name string + var name ast.SymbolNameKey if nameType != nil && isTypeUsableAsPropertyName(nameType) { name = getPropertyNameFromType(nameType) } @@ -996,14 +996,14 @@ func isKnownGenericTypeName(name string) bool { } func (c *Checker) GetFirstTypeArgumentFromKnownType(t *Type) *Type { - if t.objectFlags&ObjectFlagsReference != 0 && t.symbol != nil && isKnownGenericTypeName(t.symbol.Name) { - symbol := c.getGlobalSymbol(t.symbol.Name, ast.SymbolFlagsType, nil) + if t.objectFlags&ObjectFlagsReference != 0 && t.symbol != nil && isKnownGenericTypeName(ast.UnescapeLeadingUnderscores(t.symbol.Name)) { + symbol := c.getGlobalSymbol(ast.UnescapeLeadingUnderscores(t.symbol.Name), ast.SymbolFlagsType, nil) if symbol != nil && symbol == t.Target().symbol { return core.FirstOrNil(c.getTypeArguments(t)) } } - if t.alias != nil && isKnownGenericTypeName(t.alias.symbol.Name) { - symbol := c.getGlobalSymbol(t.alias.symbol.Name, ast.SymbolFlagsType, nil) + if t.alias != nil && isKnownGenericTypeName(ast.UnescapeLeadingUnderscores(t.alias.symbol.Name)) { + symbol := c.getGlobalSymbol(ast.UnescapeLeadingUnderscores(t.alias.symbol.Name), ast.SymbolFlagsType, nil) if symbol != nil && symbol == t.alias.symbol { return core.FirstOrNil(t.alias.typeArguments) } @@ -1017,8 +1017,9 @@ func (c *Checker) GetPropertySymbolsFromContextualType(node *ast.Node, contextua if name == "" { return nil } + symbolName := ast.EscapeLeadingUnderscores(name) if contextualType.flags&TypeFlagsUnion == 0 { - if symbol := c.getPropertyOfType(contextualType, name); symbol != nil { + if symbol := c.getPropertyOfType(contextualType, symbolName); symbol != nil { return []*ast.Symbol{symbol} } return nil @@ -1030,17 +1031,17 @@ func (c *Checker) GetPropertySymbolsFromContextualType(node *ast.Node, contextua }) } discriminatedPropertySymbols := core.MapNonNil(filteredTypes, func(t *Type) *ast.Symbol { - return c.getPropertyOfType(t, name) + return c.getPropertyOfType(t, symbolName) }) if unionSymbolOk && (len(discriminatedPropertySymbols) == 0 || len(discriminatedPropertySymbols) == len(contextualType.Types())) { - if symbol := c.getPropertyOfType(contextualType, name); symbol != nil { + if symbol := c.getPropertyOfType(contextualType, symbolName); symbol != nil { return []*ast.Symbol{symbol} } } if len(filteredTypes) == 0 && len(discriminatedPropertySymbols) == 0 { // Bad discriminant -- do again without discriminating return core.MapNonNil(contextualType.Types(), func(t *Type) *ast.Symbol { - return c.getPropertyOfType(t, name) + return c.getPropertyOfType(t, symbolName) }) } // by eliminating duplicates we might even end up with a single symbol @@ -1061,7 +1062,7 @@ func (c *Checker) GetPropertySymbolOfDestructuringAssignment(location *ast.Node) if ast.IsArrayLiteralOrObjectLiteralDestructuringPattern(location.Parent.Parent) { // Get the type of the object or array literal and then look for property of given name in the type if typeOfObjectLiteral := c.getTypeOfAssignmentPattern(location.Parent.Parent); typeOfObjectLiteral != nil { - return c.getPropertyOfType(typeOfObjectLiteral, location.Text()) + return c.getPropertyOfType(typeOfObjectLiteral, ast.EscapeLeadingUnderscores(location.Text())) } } return nil diff --git a/internal/checker/symbolaccessibility.go b/internal/checker/symbolaccessibility.go index d17ef471908..38db9beeee0 100644 --- a/internal/checker/symbolaccessibility.go +++ b/internal/checker/symbolaccessibility.go @@ -819,7 +819,7 @@ func (c *Checker) getClassExpressionNameTable(location *ast.Node) ast.SymbolTabl if len(nameText) == 0 || classSymbol == nil { return nil } - table := ast.SymbolTable{nameText: classSymbol} + table := ast.SymbolTable{ast.EscapeLeadingUnderscores(nameText): classSymbol} if c.classExpressionNameTables == nil { c.classExpressionNameTables = make(map[ast.NodeId]ast.SymbolTable) } diff --git a/internal/checker/types.go b/internal/checker/types.go index 41707735ed0..dd8153e9631 100644 --- a/internal/checker/types.go +++ b/internal/checker/types.go @@ -203,8 +203,8 @@ type AliasSymbolLinks struct { // Links for module symbols type ModuleSymbolLinks struct { - resolvedExports ast.SymbolTable // Resolved exports of module or combined early- and late-bound static members of a class. - typeOnlyExportStarMap map[string]*ast.Node // Set on a module symbol when some of its exports were resolved through a 'export type * from "mod"' declaration + resolvedExports ast.SymbolTable // Resolved exports of module or combined early- and late-bound static members of a class. + typeOnlyExportStarMap map[ast.SymbolNameKey]*ast.Node // Set on a module symbol when some of its exports were resolved through a 'export type * from "mod"' declaration exportsChecked bool } @@ -905,7 +905,7 @@ func (t *LiteralType) String() string { type UniqueESSymbolType struct { TypeBase - name string + name ast.SymbolNameKey } // ConstrainedType (type with computed base constraint) @@ -1140,9 +1140,9 @@ type UnionType struct { UnionOrIntersectionType resolvedReducedType *Type regularType *Type - origin *Type // Denormalized union, intersection, or index type in which union originates - keyPropertyName string // Property with unique unit type that exists in every object/intersection in union type - constituentMap map[*Type]*Type // Constituents keyed by unit type discriminants + origin *Type // Denormalized union, intersection, or index type in which union originates + keyPropertyName ast.SymbolNameKey // Property with unique unit type that exists in every object/intersection in union type + constituentMap map[*Type]*Type // Constituents keyed by unit type discriminants } // IntersectionType diff --git a/internal/checker/utilities.go b/internal/checker/utilities.go index 490d6887f8d..696232b2967 100644 --- a/internal/checker/utilities.go +++ b/internal/checker/utilities.go @@ -359,7 +359,7 @@ func (c *Checker) compareSymbolsWorker(s1, s2 *ast.Symbol) int { } else if len(s2.Declarations) != 0 { return 1 } - if r := strings.Compare(s1.Name, s2.Name); r != 0 { + if r := strings.Compare(s1.Name.EscapedText(), s2.Name.EscapedText()); r != 0 { return r } // Fall back to symbol IDs. This is a last resort that should happen only when symbols have @@ -578,7 +578,7 @@ func compareTypeNames(t1, t2 *Type) int { if s2 == nil { return -1 } - return strings.Compare(s1.Name, s2.Name) + return strings.Compare(s1.Name.EscapedText(), s2.Name.EscapedText()) } func getTypeNameSymbol(t *Type) *ast.Symbol { @@ -860,12 +860,12 @@ func isTypeUsableAsPropertyName(t *Type) bool { /** * Gets the symbolic name for a member from its type. */ -func getPropertyNameFromType(t *Type) string { +func getPropertyNameFromType(t *Type) ast.SymbolNameKey { switch { case t.flags&TypeFlagsStringLiteral != 0: - return t.AsLiteralType().value.(string) + return ast.EscapeLeadingUnderscores(t.AsLiteralType().value.(string)) case t.flags&TypeFlagsNumberLiteral != 0: - return t.AsLiteralType().value.(jsnum.Number).String() + return ast.EscapeLeadingUnderscores(t.AsLiteralType().value.(jsnum.Number).String()) case t.flags&TypeFlagsUniqueESSymbol != 0: return t.AsUniqueESSymbolType().name } @@ -957,11 +957,11 @@ func IsPrivateIdentifierSymbol(symbol *ast.Symbol) bool { if symbol == nil { return false } - return strings.HasPrefix(symbol.Name, ast.InternalSymbolNamePrefix+"#") + return strings.HasPrefix(symbol.Name.EscapedText(), ast.InternalSymbolNamePrefix+"#") } -func isLateBoundName(name string) bool { - return len(name) >= 2 && name[0] == '\xfe' && name[1] == '@' +func isLateBoundName(name ast.SymbolNameKey) bool { + return len(name) >= 3 && name[0] == '_' && name[1] == '_' && name[2] == '@' } func isObjectOrArrayLiteralType(t *Type) bool { @@ -1542,7 +1542,7 @@ func tryGetPropertyAccessOrIdentifierToString(expr *ast.Node) string { case ast.IsElementAccessExpression(expr): baseStr := tryGetPropertyAccessOrIdentifierToString(expr.Expression()) if baseStr != "" && ast.IsPropertyName(expr.AsElementAccessExpression().ArgumentExpression) { - return baseStr + "." + ast.GetPropertyNameForPropertyNameNode(expr.AsElementAccessExpression().ArgumentExpression) + return baseStr + "." + ast.UnescapeLeadingUnderscores(ast.GetPropertyNameForPropertyNameNode(expr.AsElementAccessExpression().ArgumentExpression)) } case ast.IsIdentifier(expr): return expr.Text() @@ -1593,11 +1593,10 @@ func getAnyImportSyntax(node *ast.Node) *ast.Node { return importNode } -// A reserved member name consists of the byte 0xFE (which is an invalid UTF-8 encoding) followed by one or more -// characters where the first character is not '@' or '#'. The '@' character indicates that the name is denoted by -// a well known ES Symbol instance and the '#' character indicates that the name is a PrivateIdentifier. -func isReservedMemberName(name string) bool { - return len(name) >= 2 && name[0] == '\xFE' && name[1] != '@' && name[1] != '#' +// A reserved member name starts with "__", followed by a character other than "_", "@", or "#". +// The "@" character indicates a well-known ES Symbol and "#" indicates a private identifier. +func isReservedMemberName(name ast.SymbolNameKey) bool { + return len(name) >= 3 && name[0] == '_' && name[1] == '_' && name[2] != '_' && name[2] != '@' && name[2] != '#' } func introducesArgumentsExoticObject(node *ast.Node) bool { @@ -1628,7 +1627,7 @@ func SkipAlias(symbol *ast.Symbol, checker *Checker) *ast.Symbol { // True if the symbol is for an external module, as opposed to a namespace. func IsExternalModuleSymbol(moduleSymbol *ast.Symbol) bool { - firstRune, _ := utf8.DecodeRuneInString(moduleSymbol.Name) + firstRune, _ := utf8.DecodeRuneInString(ast.UnescapeLeadingUnderscores(moduleSymbol.Name)) return moduleSymbol.Flags&ast.SymbolFlagsModule != 0 && firstRune == '"' } diff --git a/internal/ls/autoimport/export.go b/internal/ls/autoimport/export.go index cb5278fab0d..97f72d14f6c 100644 --- a/internal/ls/autoimport/export.go +++ b/internal/ls/autoimport/export.go @@ -73,14 +73,14 @@ func (e *Export) Name() string { if e.localName != "" { return e.localName } - if e.ExportName == ast.InternalSymbolNameExportEquals { + if ast.EscapeLeadingUnderscores(e.ExportName) == ast.InternalSymbolNameExportEquals { return e.Target.ExportName } return e.ExportName } func (e *Export) IsRenameable() bool { - return e.ExportName == ast.InternalSymbolNameExportEquals || e.ExportName == ast.InternalSymbolNameDefault + return ast.EscapeLeadingUnderscores(e.ExportName) == ast.InternalSymbolNameExportEquals || ast.EscapeLeadingUnderscores(e.ExportName) == ast.InternalSymbolNameDefault } func (e *Export) AmbientModuleName() string { @@ -117,13 +117,13 @@ func SymbolToExport(symbol *ast.Symbol, ch *checker.Checker) *Export { moduleFileName := file.FileName() target := ch.GetMergedSymbol(ch.SkipAlias(symbol)) - if export := tryGetModuleExport(ast.InternalSymbolNameDefault, target, moduleSymbol, ch, moduleID, moduleFileName, file); export != nil { + if export := tryGetModuleExport(ast.UnescapeLeadingUnderscores(ast.InternalSymbolNameDefault), target, moduleSymbol, ch, moduleID, moduleFileName, file); export != nil { return export } - if export := tryGetModuleExport(ast.InternalSymbolNameExportEquals, target, moduleSymbol, ch, moduleID, moduleFileName, file); export != nil { + if export := tryGetModuleExport(ast.UnescapeLeadingUnderscores(ast.InternalSymbolNameExportEquals), target, moduleSymbol, ch, moduleID, moduleFileName, file); export != nil { return export } - return tryGetModuleExport(symbol.Name, target, moduleSymbol, ch, moduleID, moduleFileName, file) + return tryGetModuleExport(ast.UnescapeLeadingUnderscores(symbol.Name), target, moduleSymbol, ch, moduleID, moduleFileName, file) } func tryGetModuleExport(exportName string, target *ast.Symbol, moduleSymbol *ast.Symbol, ch *checker.Checker, moduleID ModuleID, moduleFileName string, file *ast.SourceFile) *Export { diff --git a/internal/ls/autoimport/extract.go b/internal/ls/autoimport/extract.go index dc0a1db7e44..19b13ee34d8 100644 --- a/internal/ls/autoimport/extract.go +++ b/internal/ls/autoimport/extract.go @@ -164,7 +164,7 @@ func (e *exportExtractor) extractFromModuleDeclaration(decl *ast.ModuleDeclarati } } -func (e *symbolExtractor) extractFromSymbol(name string, symbol *ast.Symbol, moduleID ModuleID, moduleFileName string, file *ast.SourceFile, exports *[]*Export) { +func (e *symbolExtractor) extractFromSymbol(name ast.SymbolNameKey, symbol *ast.Symbol, moduleID ModuleID, moduleFileName string, file *ast.SourceFile, exports *[]*Export) { if shouldIgnoreSymbol(symbol) { return } @@ -191,12 +191,12 @@ func (e *symbolExtractor) extractFromSymbol(name string, symbol *ast.Symbol, mod if parent != nil && parent.IsExternalModule() { if targetModuleID, ok := e.getModuleIDForSymbol(parent); ok { export.Target = ExportID{ - ExportName: reexportedSymbol.Name, + ExportName: ast.UnescapeLeadingUnderscores(reexportedSymbol.Name), ModuleID: targetModuleID, } } } - export.through = ast.InternalSymbolNameExportStar + export.through = ast.UnescapeLeadingUnderscores(ast.InternalSymbolNameExportStar) *exports = append(*exports, export) } } @@ -219,7 +219,7 @@ func (e *symbolExtractor) extractFromSymbol(name string, symbol *ast.Symbol, mod if innerName != ast.InternalSymbolNameExportStar { export, _ := e.createExport(namedExport, moduleID, moduleFileName, syntax, file, checkerLease) if export != nil { - export.through = name + export.through = ast.UnescapeLeadingUnderscores(name) *exports = append(*exports, export) } } @@ -234,9 +234,9 @@ func (e *symbolExtractor) extractFromSymbol(name string, symbol *ast.Symbol, mod *exports = slices.Grow(*exports, len(expression.AsObjectLiteralExpression().Properties.Nodes)) for _, prop := range expression.AsObjectLiteralExpression().Properties.Nodes { if ast.IsShorthandPropertyAssignment(prop) || ast.IsPropertyAssignment(prop) && prop.AsPropertyAssignment().Name().Kind == ast.KindIdentifier { - export, _ := e.createExport(expression.Symbol().Members[prop.Name().Text()], moduleID, moduleFileName, syntax, file, checkerLease) + export, _ := e.createExport(expression.Symbol().Members[ast.EscapeLeadingUnderscores(prop.Name().Text())], moduleID, moduleFileName, syntax, file, checkerLease) if export != nil { - export.through = name + export.through = ast.UnescapeLeadingUnderscores(name) *exports = append(*exports, export) } } @@ -253,7 +253,7 @@ func (e *symbolExtractor) createExport(symbol *ast.Symbol, moduleID ModuleID, mo export := &Export{ ExportID: ExportID{ - ExportName: symbol.Name, + ExportName: ast.UnescapeLeadingUnderscores(symbol.Name), ModuleID: moduleID, }, ModuleFileName: moduleFileName, @@ -264,8 +264,8 @@ func (e *symbolExtractor) createExport(symbol *ast.Symbol, moduleID ModuleID, mo } if syntax == ExportSyntaxUMD { - export.ExportName = ast.InternalSymbolNameExportEquals - export.localName = symbol.Name + export.ExportName = ast.UnescapeLeadingUnderscores(ast.InternalSymbolNameExportEquals) + export.localName = ast.UnescapeLeadingUnderscores(symbol.Name) } var targetSymbol *ast.Symbol @@ -306,7 +306,7 @@ func (e *symbolExtractor) createExport(symbol *ast.Symbol, moduleID ModuleID, mo } } export.Target = ExportID{ - ExportName: targetSymbol.Name, + ExportName: ast.UnescapeLeadingUnderscores(targetSymbol.Name), ModuleID: targetModuleID, } } @@ -438,9 +438,9 @@ func getSyntax(symbol *ast.Symbol) ExportSyntax { func isUnusableName(name string) bool { return name == "" || name == "_default" || - name == ast.InternalSymbolNameExportStar || - name == ast.InternalSymbolNameDefault || - name == ast.InternalSymbolNameExportEquals + ast.EscapeLeadingUnderscores(name) == ast.InternalSymbolNameExportStar || + ast.EscapeLeadingUnderscores(name) == ast.InternalSymbolNameDefault || + ast.EscapeLeadingUnderscores(name) == ast.InternalSymbolNameExportEquals } // fileNameForDefaultExportName returns the best file name to use when deriving diff --git a/internal/ls/autoimport/fix.go b/internal/ls/autoimport/fix.go index 4103cdc72b9..482ebb4b5ce 100644 --- a/internal/ls/autoimport/fix.go +++ b/internal/ls/autoimport/fix.go @@ -785,7 +785,7 @@ func getImportKind(importingFile *ast.SourceFile, export *Export, program *compi case ExportSyntaxDefaultModifier, ExportSyntaxDefaultDeclaration: return lsproto.ImportKindDefault case ExportSyntaxNamed: - if export.ExportName == ast.InternalSymbolNameDefault { + if ast.EscapeLeadingUnderscores(export.ExportName) == ast.InternalSymbolNameDefault { return lsproto.ImportKindDefault } fallthrough @@ -793,7 +793,7 @@ func getImportKind(importingFile *ast.SourceFile, export *Export, program *compi return lsproto.ImportKindNamed case ExportSyntaxEquals, ExportSyntaxCommonJSModuleExports, ExportSyntaxUMD: // export.Syntax will be ExportSyntaxEquals for named exports/properties of an export='s target. - if export.ExportName != ast.InternalSymbolNameExportEquals { + if ast.EscapeLeadingUnderscores(export.ExportName) != ast.InternalSymbolNameExportEquals { return lsproto.ImportKindNamed } // !!! cache this? diff --git a/internal/ls/autoimport/import_adder.go b/internal/ls/autoimport/import_adder.go index ab0603d65be..b3f64e6fcd2 100644 --- a/internal/ls/autoimport/import_adder.go +++ b/internal/ls/autoimport/import_adder.go @@ -474,7 +474,7 @@ func getNameForExportedSymbol(symbol *ast.Symbol, preferCapitalized bool) string debug.Assert(symbol.Parent != nil, "Expected exported symbol to have module symbol as parent") return lsutil.ModuleSymbolToValidIdentifier(symbol.Parent, preferCapitalized) } - return symbol.Name + return ast.UnescapeLeadingUnderscores(symbol.Name) } func replaceFirstIdentifierOfEntityName(factory *ast.NodeFactory, name *ast.EntityName, newIdentifier *ast.IdentifierNode) *ast.EntityName { diff --git a/internal/ls/autoimport/util.go b/internal/ls/autoimport/util.go index b915890ad2b..4fd330eedef 100644 --- a/internal/ls/autoimport/util.go +++ b/internal/ls/autoimport/util.go @@ -136,7 +136,7 @@ func getDefaultLikeExportNameFromDeclaration(symbol *ast.Symbol) string { return name.Text() } if symbol.Parent != nil && !checker.IsExternalModuleSymbol(symbol.Parent) { - return symbol.Parent.Name + return ast.UnescapeLeadingUnderscores(symbol.Parent.Name) } } return "" diff --git a/internal/ls/codeactions_fixclassincorrectlyimplementsinterface.go b/internal/ls/codeactions_fixclassincorrectlyimplementsinterface.go index 756b1b340a0..51c121832d2 100644 --- a/internal/ls/codeactions_fixclassincorrectlyimplementsinterface.go +++ b/internal/ls/codeactions_fixclassincorrectlyimplementsinterface.go @@ -171,7 +171,7 @@ func getConstructor(classDeclaration *ast.Node) *ast.Node { func getMissingMembers(typeChecker *checker.Checker, classDeclaration *ast.Node, implementedTypes []*checker.Type) []*ast.Symbol { inheritedMembers := getInheritedMembers(typeChecker, classDeclaration) - seenMembers := make(map[string]*ast.Symbol) + seenMembers := make(map[ast.SymbolNameKey]*ast.Symbol) var classMembers ast.SymbolTable if classDeclaration.Symbol() != nil { diff --git a/internal/ls/codeactions_fixmissingtypeannotation.go b/internal/ls/codeactions_fixmissingtypeannotation.go index b218d270771..77843d274b0 100644 --- a/internal/ls/codeactions_fixmissingtypeannotation.go +++ b/internal/ls/codeactions_fixmissingtypeannotation.go @@ -260,7 +260,8 @@ func (f *isolatedDeclarationsFixer) createNamespaceForExpandoProperties(expandoF var newProperties []*ast.Node for _, symbol := range elements { - if !scanner.IsIdentifierText(symbol.Name, core.LanguageVariantStandard) { + name := ast.UnescapeLeadingUnderscores(symbol.Name) + if !scanner.IsIdentifierText(name, core.LanguageVariantStandard) { continue } // skip symbols that already have a variable declaration @@ -274,7 +275,7 @@ func (f *isolatedDeclarationsFixer) createNamespaceForExpandoProperties(expandoF continue } - varDecl := factory.NewVariableDeclaration(factory.NewIdentifier(symbol.Name), nil, typeNode, nil) + varDecl := factory.NewVariableDeclaration(factory.NewIdentifier(name), nil, typeNode, nil) exportToken := factory.NewToken(ast.KindExportKeyword) varDeclList := factory.NewVariableDeclarationList(factory.NewNodeList([]*ast.Node{varDecl}), ast.NodeFlagsNone) varStmt := factory.NewVariableStatement(factory.NewModifierList([]*ast.Node{exportToken}), varDeclList) @@ -1383,7 +1384,7 @@ func (f *isolatedDeclarationsFixer) addSymbolToExistingImport(sym *ast.Symbol) { // Find the module specifier for this symbol moduleSymbol := sym.Parent - symbolName := sym.Name + symbolName := ast.UnescapeLeadingUnderscores(sym.Name) // Walk the source file's import declarations to find the one importing from the same module for _, stmt := range f.sourceFile.Statements.Nodes { diff --git a/internal/ls/codeactions_importfixes.go b/internal/ls/codeactions_importfixes.go index 894510b8aca..62dfc21e972 100644 --- a/internal/ls/codeactions_importfixes.go +++ b/internal/ls/codeactions_importfixes.go @@ -258,7 +258,7 @@ func getFixesInfoForUMDImport(ctx context.Context, fixContext *CodeFixContext, t } result = append(result, &fixInfo{ fix: fix, - symbolName: umdSymbol.Name, + symbolName: ast.UnescapeLeadingUnderscores(umdSymbol.Name), errorIdentifierText: errorIdentifierText, }) } diff --git a/internal/ls/codeactions_missingmemberfixer.go b/internal/ls/codeactions_missingmemberfixer.go index bd4b8552597..79b405ebcba 100644 --- a/internal/ls/codeactions_missingmemberfixer.go +++ b/internal/ls/codeactions_missingmemberfixer.go @@ -325,7 +325,7 @@ func (f *missingMemberFixer) createSignatureDeclarationFromSignatures(signatures maxNonRestArgs := len(maxArgsSignature.Parameters()) - core.IfElse(maxArgsSignature.HasRestParameter(), 1, 0) parameterNames := make([]string, 0, len(maxArgsSignature.Parameters())) for _, symbol := range maxArgsSignature.Parameters() { - parameterNames = append(parameterNames, symbol.Name) + parameterNames = append(parameterNames, ast.UnescapeLeadingUnderscores(symbol.Name)) } parameters := createDummyParameters(f.changeTracker.NodeFactory, maxNonRestArgs, parameterNames, nil /*types*/, minArgumentCount, ast.IsInJSFile(enclosingDeclaration)) @@ -481,7 +481,7 @@ func createDeclarationName(factory *ast.NodeFactory, typeChecker *checker.Checke return declaration.Name().Clone(factory) } if symbol != nil { - return factory.NewIdentifier(symbol.Name) + return factory.NewIdentifier(ast.UnescapeLeadingUnderscores(symbol.Name)) } return nil } diff --git a/internal/ls/completions.go b/internal/ls/completions.go index e6659cec1a2..c99907b6b9c 100644 --- a/internal/ls/completions.go +++ b/internal/ls/completions.go @@ -768,7 +768,7 @@ func (l *LanguageService) getCompletionData( moduleSymbol := firstAccessibleSymbol.Parent if moduleSymbol == nil || !checker.IsExternalModuleSymbol(moduleSymbol) || - typeChecker.TryGetMemberInModuleExportsAndProperties(firstAccessibleSymbol.Name, moduleSymbol) != firstAccessibleSymbol { + typeChecker.TryGetMemberInModuleExportsAndProperties(ast.UnescapeLeadingUnderscores(firstAccessibleSymbol.Name), moduleSymbol) != firstAccessibleSymbol { symbolToOriginInfoMap[len(symbols)-1] = &symbolOriginInfo{kind: getNullableSymbolOriginInfoKind(symbolOriginInfoKindSymbolMember, insertQuestionDot)} } else { // !!! auto-import symbol @@ -868,7 +868,7 @@ func (l *LanguageService) getCompletionData( panic("getExporsOfModule() should all be defined") } isValidValueAccess := func(s *ast.Symbol) bool { - return typeChecker.IsValidPropertyAccess(valueAccessNode, s.Name) + return typeChecker.IsValidPropertyAccess(valueAccessNode, ast.UnescapeLeadingUnderscores(s.Name)) } isValidTypeAccess := func(s *ast.Symbol) bool { return symbolCanBeReferencedAtTypeLocation(s, typeChecker, collections.Set[ast.SymbolId]{}) @@ -978,12 +978,14 @@ func (l *LanguageService) getCompletionData( existingMemberNames := collections.Set[string]{} for _, member := range existingMembers { - existingMemberNames.Add(member.Name) + existingMemberNames.Add(ast.UnescapeLeadingUnderscores(member.Name)) } symbols = append( symbols, - core.Filter(members, func(member *ast.Symbol) bool { return !existingMemberNames.Has(member.Name) })..., + core.Filter(members, func(member *ast.Symbol) bool { + return !existingMemberNames.Has(ast.UnescapeLeadingUnderscores(member.Name)) + })..., ) completionKind = CompletionKindObjectPropertyDeclaration @@ -1098,7 +1100,7 @@ func (l *LanguageService) getCompletionData( objectLikeContainer.Kind == ast.KindObjectLiteralExpression for _, member := range filteredMembers { symbolId := ast.GetSymbolId(member) - if spreadMemberNames.Has(member.Name) { + if spreadMemberNames.Has(ast.UnescapeLeadingUnderscores(member.Name)) { symbolToSortTextMap[symbolId] = SortTextMemberDeclaredBySpreadAssignment } if member.Flags&ast.SymbolFlagsOptional != 0 { @@ -1245,7 +1247,7 @@ func (l *LanguageService) getCompletionData( existing.Add(element.PropertyNameOrName().Text()) } uniques := core.Filter(exports, func(symbol *ast.Symbol) bool { - return ast.SymbolName(symbol) != ast.InternalSymbolNameDefault && !existing.Has(ast.SymbolName(symbol)) + return ast.SymbolName(symbol) != ast.UnescapeLeadingUnderscores(ast.InternalSymbolNameDefault) && !existing.Has(ast.SymbolName(symbol)) }) symbols = append(symbols, uniques...) @@ -3720,7 +3722,7 @@ func getConstraintOfTypeArgumentProperty(node *ast.Node, typeChecker *checker.Ch // Try to get the reparsed node first - we may be in JSDoc. reparsed := ast.GetReparsedNodeForNode(node) if symbol := reparsed.Symbol(); symbol != nil { - return typeChecker.GetTypeOfPropertyOfContextualType(t, symbol.Name) + return typeChecker.GetTypeOfPropertyOfContextualType(t, ast.UnescapeLeadingUnderscores(symbol.Name)) } // In some cases, we won't have a corresponding symbol @@ -3947,7 +3949,7 @@ func filterObjectMembersList( } filteredSymbols := core.Filter(contextualMemberSymbols, func(m *ast.Symbol) bool { - return !existingMemberNames.Has(m.Name) + return !existingMemberNames.Has(ast.UnescapeLeadingUnderscores(m.Name)) }) return filteredSymbols, membersDeclaredBySpreadAssignment @@ -3970,7 +3972,7 @@ func setMemberDeclaredBySpreadAssignment(declaration *ast.Node, members *collect properties = t.AsStructuredType().Properties() } for _, property := range properties { - members.Add(property.Name) + members.Add(ast.UnescapeLeadingUnderscores(property.Name)) } } @@ -4139,7 +4141,7 @@ func filterClassMembersList( existingName := ast.GetPropertyNameForPropertyNameNode(member.Name()) if existingName != "" { - existingMemberNames.Add(existingName) + existingMemberNames.Add(ast.UnescapeLeadingUnderscores(existingName)) } } @@ -4237,7 +4239,9 @@ func filterJsxAttributes( } } - return core.Filter(symbols, func(a *ast.Symbol) bool { return !existingNames.Has(a.Name) }), + return core.Filter(symbols, func(a *ast.Symbol) bool { + return !existingNames.Has(ast.UnescapeLeadingUnderscores(a.Name)) + }), &membersDeclaredBySpreadAssignment } diff --git a/internal/ls/findallreferences.go b/internal/ls/findallreferences.go index 28043f859dd..849411fbd6d 100644 --- a/internal/ls/findallreferences.go +++ b/internal/ls/findallreferences.go @@ -392,7 +392,7 @@ func skipPastExportOrImportSpecifierOrUnion(symbol *ast.Symbol, node *ast.Node, panic(fmt.Sprintf("Unexpected symbol at %s: %s", node.Kind.String(), symbol.Name)) } if decl.Parent.Kind == ast.KindTypeLiteral && decl.Parent.Parent.Kind == ast.KindUnionType { - return checker.GetPropertyOfType(checker.GetTypeFromTypeNode(decl.Parent.Parent), symbol.Name) + return checker.GetPropertyOfType(checker.GetTypeFromTypeNode(decl.Parent.Parent), ast.UnescapeLeadingUnderscores(symbol.Name)) } return nil }) @@ -2500,7 +2500,7 @@ func (state *refState) forEachRelatedSymbol( } // Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions if rootSymbol.Parent != nil && rootSymbol.Parent.Flags&(ast.SymbolFlagsClass|ast.SymbolFlagsInterface) != 0 && allowBaseTypes(rootSymbol) { - result := getPropertySymbolsFromBaseTypes(rootSymbol.Parent, rootSymbol.Name, state.checker, func(base *ast.Symbol) *ast.Symbol { + result := getPropertySymbolsFromBaseTypes(rootSymbol.Parent, ast.UnescapeLeadingUnderscores(rootSymbol.Name), state.checker, func(base *ast.Symbol) *ast.Symbol { return cbSymbol(sym, rootSymbol, base) }) if result != nil { @@ -2567,7 +2567,10 @@ func (state *refState) forEachRelatedSymbol( } if symbol.ValueDeclaration != nil && ast.IsParameterPropertyDeclaration(symbol.ValueDeclaration, symbol.ValueDeclaration.Parent) { - paramProp1, paramProp2 := state.checker.GetSymbolsOfParameterPropertyDeclaration(symbol.ValueDeclaration, symbol.Name) + paramProp1, paramProp2 := state.checker.GetSymbolsOfParameterPropertyDeclaration( + symbol.ValueDeclaration, + ast.UnescapeLeadingUnderscores(symbol.Name), + ) debug.Assert( paramProp1.Flags&ast.SymbolFlagsFunctionScopedVariable != 0 && paramProp2.Flags&ast.SymbolFlagsClassMember != 0, "GetSymbolsOfParameterPropertyDeclaration must return (parameter, member) pair", diff --git a/internal/ls/hover.go b/internal/ls/hover.go index 22d2e93982f..0c30404336b 100644 --- a/internal/ls/hover.go +++ b/internal/ls/hover.go @@ -951,14 +951,14 @@ func getJSDocOrTag(c *checker.Checker, node *ast.Node) *ast.Node { // This correctly handles intersection constructor types from mixins // (e.g., typeof MixinClass & T) by preserving the full intersection. staticBaseType := c.GetApparentType(c.GetBaseConstructorTypeOfClass(classType)) - if prop := c.GetPropertyOfType(staticBaseType, symbol.Name); prop != nil && prop.ValueDeclaration != nil { + if prop := c.GetPropertyOfType(staticBaseType, ast.UnescapeLeadingUnderscores(symbol.Name)); prop != nil && prop.ValueDeclaration != nil { if jsDoc := getJSDocOrTag(c, prop.ValueDeclaration); jsDoc != nil { return jsDoc } } } else { for _, baseType := range c.GetBaseTypes(classType) { - if prop := c.GetPropertyOfType(baseType, symbol.Name); prop != nil && prop.ValueDeclaration != nil { + if prop := c.GetPropertyOfType(baseType, ast.UnescapeLeadingUnderscores(symbol.Name)); prop != nil && prop.ValueDeclaration != nil { if jsDoc := getJSDocOrTag(c, prop.ValueDeclaration); jsDoc != nil { return jsDoc } diff --git a/internal/ls/importTracker.go b/internal/ls/importTracker.go index 983a8a2aa66..9263eaa9268 100644 --- a/internal/ls/importTracker.go +++ b/internal/ls/importTracker.go @@ -356,7 +356,8 @@ func getSearchesFromDirectImports( isNameMatch := func(name string) bool { // Use name of "default" even in `export =` case because we may have allowSyntheticDefaultImports - return name == exportSymbol.Name || exportKind != ExportKindNamed && name == ast.InternalSymbolNameDefault + return name == ast.UnescapeLeadingUnderscores(exportSymbol.Name) || + exportKind != ExportKindNamed && name == ast.UnescapeLeadingUnderscores(ast.InternalSymbolNameDefault) } // `import x = require("./x")` or `import * as x from "./x"`. @@ -384,7 +385,7 @@ func getSearchesFromDirectImports( singleReferences = append(singleReferences, propertyName) // If renaming `{ foo as bar }`, don't touch `bar`, just `foo`. // But do rename `foo` in ` { default as foo }` if that's the original export name. - if !isForRename || name.Text() == exportSymbol.Name { + if !isForRename || name.Text() == ast.UnescapeLeadingUnderscores(exportSymbol.Name) { // Search locally for `bar`. addSearch(name, checker.GetSymbolAtLocation(name)) } @@ -592,7 +593,9 @@ func getImportOrExportSymbol(node *ast.Node, symbol *ast.Symbol, checker *checke // If `importedName` is undefined, do continue searching as the export is anonymous. // (All imports returned from this function will be ignored anyway if we are in rename and this is a not a named export.) importedName := symbolNameNoDefault(importedSymbol) - if importedName == "" || importedName == ast.InternalSymbolNameDefault || importedName == symbol.Name { + if importedName == "" || + importedName == ast.UnescapeLeadingUnderscores(ast.InternalSymbolNameDefault) || + importedName == ast.UnescapeLeadingUnderscores(symbol.Name) { return &ImportExportSymbol{ kind: ImpExpKindImport, symbol: importedSymbol, @@ -700,7 +703,7 @@ func getExportEqualsLocalSymbol(importedSymbol *ast.Symbol, checker *checker.Che func symbolNameNoDefault(symbol *ast.Symbol) string { if symbol.Name != ast.InternalSymbolNameDefault { - return symbol.Name + return ast.UnescapeLeadingUnderscores(symbol.Name) } for _, decl := range symbol.Declarations { name := ast.GetNameOfDeclaration(decl) diff --git a/internal/ls/inlay_hints.go b/internal/ls/inlay_hints.go index a1923826cb5..018c3d5e700 100644 --- a/internal/ls/inlay_hints.go +++ b/internal/ls/inlay_hints.go @@ -866,7 +866,7 @@ func (s *inlayHintState) getParameterIdentifierInfoAtPosition(signature *checker if pos == paramCount { return ¶meterInfo{ parameter: restId, - name: restParameter.Name, + name: ast.UnescapeLeadingUnderscores(restParameter.Name), isRestParameter: true, } } diff --git a/internal/ls/lsutil/utilities.go b/internal/ls/lsutil/utilities.go index 745d3a7221c..9fa1ae0bd46 100644 --- a/internal/ls/lsutil/utilities.go +++ b/internal/ls/lsutil/utilities.go @@ -114,7 +114,7 @@ func GetQuotePreference(sourceFile *ast.SourceFile, preferences UserPreferences) } func ModuleSymbolToValidIdentifier(moduleSymbol *ast.Symbol, forceCapitalize bool) string { - return ModuleSpecifierToValidIdentifier(stringutil.StripQuotes(moduleSymbol.Name), forceCapitalize) + return ModuleSpecifierToValidIdentifier(stringutil.StripQuotes(ast.UnescapeLeadingUnderscores(moduleSymbol.Name)), forceCapitalize) } func ModuleSpecifierToValidIdentifier(moduleSpecifier string, forceCapitalize bool) string { diff --git a/internal/ls/signaturehelp.go b/internal/ls/signaturehelp.go index c837656666e..909f8b45d69 100644 --- a/internal/ls/signaturehelp.go +++ b/internal/ls/signaturehelp.go @@ -296,10 +296,11 @@ func (l *LanguageService) createSignatureHelpItems(ctx context.Context, candidat var callTargetDisplayParts strings.Builder // A contextual signature for an anonymous inline function type (e.g. a callback // argument) has a synthetic symbol whose name is an internal marker such as - // "\xFEtype". There is no meaningful name to show, so render the signature with + // "__type". There is no meaningful name to show, so render the signature with // no prefix (as we already do when there is no call target symbol) rather than // leaking the internal name. - if callTargetSymbol != nil && !strings.HasPrefix(callTargetSymbol.Name, ast.InternalSymbolNamePrefix) { + if callTargetSymbol != nil && + !strings.HasPrefix(callTargetSymbol.Name.EscapedText(), ast.InternalSymbolNamePrefix) { if useFullPrefix { callTargetDisplayParts.WriteString(c.SymbolToStringEx(callTargetSymbol, sourceFile.AsNode(), ast.SymbolFlagsNone, checker.SymbolFormatFlagsUseAliasDefinedOutsideCurrentScope)) } else { diff --git a/internal/ls/string_completions.go b/internal/ls/string_completions.go index f5240bcf329..ddecf0f659f 100644 --- a/internal/ls/string_completions.go +++ b/internal/ls/string_completions.go @@ -393,7 +393,7 @@ func (l *LanguageService) getStringLiteralCompletionEntries( return n.PropertyNameOrName().Text() })...) uniques := core.Filter(exports, func(e *ast.Symbol) bool { - return e.Name != ast.InternalSymbolNameDefault && !existing.Has(e.Name) + return e.Name != ast.InternalSymbolNameDefault && !existing.Has(ast.UnescapeLeadingUnderscores(e.Name)) }) return &stringLiteralCompletions{ fromProperties: &completionsFromProperties{ @@ -515,7 +515,9 @@ func fromUnionableLiteralType( fromProperties: &completionsFromProperties{ symbols: core.Filter( result.symbols, - func(s *ast.Symbol) bool { return !slices.Contains(alreadyUsedTypes, s.Name) }, + func(s *ast.Symbol) bool { + return !slices.Contains(alreadyUsedTypes, ast.UnescapeLeadingUnderscores(s.Name)) + }, ), hasIndexSignature: result.hasIndexSignature, }, @@ -882,7 +884,7 @@ func getAmbientModuleCompletions(fragment string, fragmentDirectory string, type ambientModules := typeChecker.GetAmbientModules() var nonRelativeModuleNames []string for _, sym := range ambientModules { - moduleName := stringutil.StripQuotes(sym.Name) + moduleName := stringutil.StripQuotes(ast.UnescapeLeadingUnderscores(sym.Name)) if strings.HasPrefix(moduleName, fragment) && !strings.Contains(moduleName, "*") { nonRelativeModuleNames = append(nonRelativeModuleNames, moduleName) } @@ -1024,7 +1026,7 @@ func getSupportedExtensionsForModuleResolution(options *core.CompilerOptions, ch if checker != nil { ambientModules := checker.GetAmbientModules() for _, module := range ambientModules { - name := stringutil.StripQuotes(module.Name) + name := stringutil.StripQuotes(ast.UnescapeLeadingUnderscores(module.Name)) if !strings.HasPrefix(name, "*.") || strings.Contains(name, "/") { continue } @@ -2058,7 +2060,7 @@ func (l *LanguageService) stringLiteralCompletionDetails( case completion.fromProperties != nil: properties := completion.fromProperties for _, symbol := range properties.symbols { - if symbol.Name == name { + if ast.UnescapeLeadingUnderscores(symbol.Name) == name { return l.createCompletionDetailsForSymbol(item, symbol, checker, location, position, docFormat) } } diff --git a/internal/printer/namegenerator.go b/internal/printer/namegenerator.go index 2fd38affb4a..d249a32eef9 100644 --- a/internal/printer/namegenerator.go +++ b/internal/printer/namegenerator.go @@ -366,7 +366,7 @@ func isUniqueLocalName(name string, container *ast.Node) bool { locals := node.Locals() if locals != nil { // We conservatively include alias symbols to cover cases where they're emitted as locals - if local, ok := locals[name]; ok && local.Flags&(ast.SymbolFlagsValue|ast.SymbolFlagsExportValue|ast.SymbolFlagsAlias) != 0 { + if local, ok := locals[ast.EscapeLeadingUnderscores(name)]; ok && local.Flags&(ast.SymbolFlagsValue|ast.SymbolFlagsExportValue|ast.SymbolFlagsAlias) != 0 { return false } } diff --git a/internal/testutil/fsbaselineutil/differ.go b/internal/testutil/fsbaselineutil/differ.go index bb01153fed1..b2feeb1eea1 100644 --- a/internal/testutil/fsbaselineutil/differ.go +++ b/internal/testutil/fsbaselineutil/differ.go @@ -94,12 +94,12 @@ func (d *FSDiffer) BaselineFSwithDiff(baseline io.Writer) { *d.WrittenFiles = collections.SyncSet[string]{} // Reset written files after baseline } -var internalSymbolRegex = regexp.MustCompile(`\x{FFFD}@[^@]+@[0-9]+`) +var internalSymbolRegex = regexp.MustCompile(`__@[^@]+@[0-9]+`) -// Replaces internal symbol names of shape \uFFFD@symbolName@123 with \uFFFD@symbolName@ -// // to avoid baselining differences in symbol ids, which can change between runs. +// Replaces internal symbol names of shape __@symbolName@123 with __@symbolName@ +// to avoid baselining differences in symbol ids, which can change between runs. func SanitizeInternalSymbolName(s string) string { - if !strings.Contains(s, "\uFFFD@") { + if !strings.Contains(s, "__@") { return s } return internalSymbolRegex.ReplaceAllStringFunc(s, func(match string) string { diff --git a/internal/testutil/tsbaseline/type_symbol_baseline.go b/internal/testutil/tsbaseline/type_symbol_baseline.go index 920a122057b..36304f09413 100644 --- a/internal/testutil/tsbaseline/type_symbol_baseline.go +++ b/internal/testutil/tsbaseline/type_symbol_baseline.go @@ -421,7 +421,7 @@ func (walker *typeWriterWalker) writeTypeOrSymbol(node *ast.Node, isSymbolWalk b var symbolString strings.Builder symbolString.Grow(256) symbolString.WriteString("Symbol(") - symbolString.WriteString(ast.EscapeAllInternalSymbolNames(fileChecker.SymbolToStringEx(symbol, node.Parent, ast.SymbolFlagsNone, checker.SymbolFormatFlagsAllowAnyNodeKind))) + symbolString.WriteString(fileChecker.SymbolToStringEx(symbol, node.Parent, ast.SymbolFlagsNone, checker.SymbolFormatFlagsAllowAnyNodeKind)) count := 0 for _, declaration := range symbol.Declarations { if count >= 5 { diff --git a/internal/tracing/tracing.go b/internal/tracing/tracing.go index 7300cfe12f5..04e561deae8 100644 --- a/internal/tracing/tracing.go +++ b/internal/tracing/tracing.go @@ -605,9 +605,9 @@ func (t *typeTracer) buildTypeDescriptor(typ TracedType, recursionIdentityMap ma // Symbol name - escape the internal symbol name prefix for valid JSON if sym := aliasSymbol; sym != nil { - desc.SymbolName = ast.EscapeAllInternalSymbolNames(sym.Name) + desc.SymbolName = ast.UnescapeLeadingUnderscores(sym.Name) } else if symbol != nil { - desc.SymbolName = ast.EscapeAllInternalSymbolNames(symbol.Name) + desc.SymbolName = ast.UnescapeLeadingUnderscores(symbol.Name) } // Tuple flag diff --git a/internal/transformers/declarations/transform.go b/internal/transformers/declarations/transform.go index 3309e4a4f3d..3e0a27b4b64 100644 --- a/internal/transformers/declarations/transform.go +++ b/internal/transformers/declarations/transform.go @@ -2795,7 +2795,7 @@ func (tx *DeclarationTransformer) transformExpandoAssignment(node *ast.BinaryExp declarationData.Symbol = host containerData := synthesizedNamespace.LocalsContainerData() containerData.Locals = make(ast.SymbolTable, 0) - containerData.Locals[localName.Text()] = symbol + containerData.Locals[ast.EscapeLeadingUnderscores(localName.Text())] = symbol oldEnclosing := tx.enclosingDeclaration tx.enclosingDeclaration = synthesizedNamespace diff --git a/testdata/baselines/reference/submodule/compiler/enumWithBigint.types b/testdata/baselines/reference/submodule/compiler/enumWithBigint.types index 0c7bfd2a40f..94561414199 100644 --- a/testdata/baselines/reference/submodule/compiler/enumWithBigint.types +++ b/testdata/baselines/reference/submodule/compiler/enumWithBigint.types @@ -5,7 +5,7 @@ enum E { >E : E 0n = 0, ->0n : (typeof E)["\uFFFDmissing"] +>0n : E.__missing >0 : 0 } diff --git a/testdata/baselines/reference/submodule/compiler/enumWithBigint.types.diff b/testdata/baselines/reference/submodule/compiler/enumWithBigint.types.diff deleted file mode 100644 index a89645142d2..00000000000 --- a/testdata/baselines/reference/submodule/compiler/enumWithBigint.types.diff +++ /dev/null @@ -1,10 +0,0 @@ ---- old.enumWithBigint.types -+++ new.enumWithBigint.types -@@= skipped -4, +4 lines =@@ - >E : E - - 0n = 0, -->0n : E.__missing -+>0n : (typeof E)["\uFFFDmissing"] - >0 : 0 - } diff --git a/testdata/baselines/reference/submodule/conformance/privateNameEnum.types b/testdata/baselines/reference/submodule/conformance/privateNameEnum.types index 248386f34c6..0926d029a18 100644 --- a/testdata/baselines/reference/submodule/conformance/privateNameEnum.types +++ b/testdata/baselines/reference/submodule/conformance/privateNameEnum.types @@ -5,6 +5,6 @@ enum E { >E : E #x ->#x : (typeof E)["\uFFFDmissing"] +>#x : E.__missing } diff --git a/testdata/baselines/reference/submodule/conformance/privateNameEnum.types.diff b/testdata/baselines/reference/submodule/conformance/privateNameEnum.types.diff deleted file mode 100644 index ffa5b4709aa..00000000000 --- a/testdata/baselines/reference/submodule/conformance/privateNameEnum.types.diff +++ /dev/null @@ -1,9 +0,0 @@ ---- old.privateNameEnum.types -+++ new.privateNameEnum.types -@@= skipped -4, +4 lines =@@ - >E : E - - #x -->#x : E.__missing -+>#x : (typeof E)["\uFFFDmissing"] - } diff --git a/testdata/baselines/reference/tsc/incremental/internal-symbolname-in-tsbuildInfo.js b/testdata/baselines/reference/tsc/incremental/internal-symbolname-in-tsbuildInfo.js index e33fcabf4b8..089e5b8d71d 100644 --- a/testdata/baselines/reference/tsc/incremental/internal-symbolname-in-tsbuildInfo.js +++ b/testdata/baselines/reference/tsc/incremental/internal-symbolname-in-tsbuildInfo.js @@ -104,7 +104,7 @@ Output:: 8 ...files,    ~~~~~~~~ -a.ts:5:5 - error TS2783: '�@iterator@' is specified more than once, so this usage will be overwritten. +a.ts:5:5 - error TS2783: '__@iterator@' is specified more than once, so this usage will be overwritten. 5 [Symbol.iterator]: function* (): IterableIterator {    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -147,7 +147,7 @@ Output:: 8 ...files,    ~~~~~~~~ -a.ts:5:5 - error TS2783: '�@iterator@' is specified more than once, so this usage will be overwritten. +a.ts:5:5 - error TS2783: '__@iterator@' is specified more than once, so this usage will be overwritten. 5 [Symbol.iterator]: function* (): IterableIterator {    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -181,7 +181,7 @@ Output:: 8 ...files,    ~~~~~~~~ -a.ts:5:5 - error TS2783: '�@iterator@' is specified more than once, so this usage will be overwritten. +a.ts:5:5 - error TS2783: '__@iterator@' is specified more than once, so this usage will be overwritten. 5 [Symbol.iterator]: function* (): IterableIterator {    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -199,7 +199,7 @@ Found 2 errors in the same file, starting at: a.ts:3 //// [/home/src/workspaces/project/a.js] *rewrite with same content* //// [/home/src/workspaces/project/tsconfig.tsbuildinfo] *new* -{"version":"FakeTSVersion","root":[3],"fileNames":["lib.es2015.iterable.d.ts","lib.es2017.full.d.ts","./a.ts"],"fileInfos":[{"version":"47799ad4d7599a69644aa267bcd5dc4c-interface SymbolConstructor {\n readonly iterator: unique symbol;\n}\ninterface IteratorYieldResult {\n done?: false;\n value: TYield;\n}\ninterface IteratorReturnResult {\n done: true;\n value: TReturn;\n}\ntype IteratorResult = IteratorYieldResult | IteratorReturnResult;\ninterface Iterator {\n // NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places.\n next(...[value]: [] | [TNext]): IteratorResult;\n return?(value?: TReturn): IteratorResult;\n throw?(e?: any): IteratorResult;\n}\ninterface Iterable {\n [Symbol.iterator](): Iterator;\n}\ninterface IterableIterator extends Iterator {\n [Symbol.iterator](): IterableIterator;\n}\ninterface IteratorObject extends Iterator {\n [Symbol.iterator](): IteratorObject;\n}\ntype BuiltinIteratorReturn = intrinsic;\ninterface ArrayIterator extends IteratorObject {\n [Symbol.iterator](): ArrayIterator;\n}\ninterface Array {\n [Symbol.iterator](): ArrayIterator;\n entries(): ArrayIterator<[number, T]>;\n keys(): ArrayIterator;\n values(): ArrayIterator;\n}","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"90486e388c4cd8c8ad802ceeba94c3b2-/// \ninterface File {\n}\ninterface FileList {\n readonly length: number;\n item(index: number): File | null;\n [index: number]: File;\n [Symbol.iterator](): ArrayIterator;\n}/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ninterface SymbolConstructor {\n (desc?: string | number): symbol;\n for(name: string): symbol;\n readonly toStringTag: symbol;\n}\ndeclare var Symbol: SymbolConstructor;\ninterface Symbol {\n readonly [Symbol.toStringTag]: string;\n}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"0b263ea9c85854f9c9a16d8f45c58df4-const createFileListFromFiles = (files: File[]): FileList => {\nconst fileList: FileList = {\n length: files.length,\n item: (index: number): File | null => files[index] || null,\n [Symbol.iterator]: function* (): IterableIterator {\n for (const file of files) yield file;\n },\n ...files,\n} as unknown as FileList;\n\nreturn fileList;\n};","affectsGlobalScope":true,"impliedNodeFormat":1}],"options":{"strict":true,"target":4,"esModuleInterop":true},"semanticDiagnosticsPerFile":[[3,[{"pos":96,"end":116,"code":2783,"category":1,"messageKey":"_0_is_specified_more_than_once_so_this_usage_will_be_overwritten_2783","messageArgs":["length"],"relatedInformation":[{"pos":297,"end":305,"code":2785,"category":1,"messageKey":"This_spread_always_overwrites_this_property_2785"}]},{"pos":186,"end":291,"code":2783,"category":1,"messageKey":"_0_is_specified_more_than_once_so_this_usage_will_be_overwritten_2783","messageArgs":["�@iterator@"],"relatedInformation":[{"pos":297,"end":305,"code":2785,"category":1,"messageKey":"This_spread_always_overwrites_this_property_2785"}]}]]]} +{"version":"FakeTSVersion","root":[3],"fileNames":["lib.es2015.iterable.d.ts","lib.es2017.full.d.ts","./a.ts"],"fileInfos":[{"version":"47799ad4d7599a69644aa267bcd5dc4c-interface SymbolConstructor {\n readonly iterator: unique symbol;\n}\ninterface IteratorYieldResult {\n done?: false;\n value: TYield;\n}\ninterface IteratorReturnResult {\n done: true;\n value: TReturn;\n}\ntype IteratorResult = IteratorYieldResult | IteratorReturnResult;\ninterface Iterator {\n // NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places.\n next(...[value]: [] | [TNext]): IteratorResult;\n return?(value?: TReturn): IteratorResult;\n throw?(e?: any): IteratorResult;\n}\ninterface Iterable {\n [Symbol.iterator](): Iterator;\n}\ninterface IterableIterator extends Iterator {\n [Symbol.iterator](): IterableIterator;\n}\ninterface IteratorObject extends Iterator {\n [Symbol.iterator](): IteratorObject;\n}\ntype BuiltinIteratorReturn = intrinsic;\ninterface ArrayIterator extends IteratorObject {\n [Symbol.iterator](): ArrayIterator;\n}\ninterface Array {\n [Symbol.iterator](): ArrayIterator;\n entries(): ArrayIterator<[number, T]>;\n keys(): ArrayIterator;\n values(): ArrayIterator;\n}","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"90486e388c4cd8c8ad802ceeba94c3b2-/// \ninterface File {\n}\ninterface FileList {\n readonly length: number;\n item(index: number): File | null;\n [index: number]: File;\n [Symbol.iterator](): ArrayIterator;\n}/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ninterface SymbolConstructor {\n (desc?: string | number): symbol;\n for(name: string): symbol;\n readonly toStringTag: symbol;\n}\ndeclare var Symbol: SymbolConstructor;\ninterface Symbol {\n readonly [Symbol.toStringTag]: string;\n}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true,"impliedNodeFormat":1},{"version":"0b263ea9c85854f9c9a16d8f45c58df4-const createFileListFromFiles = (files: File[]): FileList => {\nconst fileList: FileList = {\n length: files.length,\n item: (index: number): File | null => files[index] || null,\n [Symbol.iterator]: function* (): IterableIterator {\n for (const file of files) yield file;\n },\n ...files,\n} as unknown as FileList;\n\nreturn fileList;\n};","affectsGlobalScope":true,"impliedNodeFormat":1}],"options":{"strict":true,"target":4,"esModuleInterop":true},"semanticDiagnosticsPerFile":[[3,[{"pos":96,"end":116,"code":2783,"category":1,"messageKey":"_0_is_specified_more_than_once_so_this_usage_will_be_overwritten_2783","messageArgs":["length"],"relatedInformation":[{"pos":297,"end":305,"code":2785,"category":1,"messageKey":"This_spread_always_overwrites_this_property_2785"}]},{"pos":186,"end":291,"code":2783,"category":1,"messageKey":"_0_is_specified_more_than_once_so_this_usage_will_be_overwritten_2783","messageArgs":["__@iterator@"],"relatedInformation":[{"pos":297,"end":305,"code":2785,"category":1,"messageKey":"This_spread_always_overwrites_this_property_2785"}]}]]]} //// [/home/src/workspaces/project/tsconfig.tsbuildinfo.readable.baseline.txt] *new* { "version": "FakeTSVersion", @@ -289,7 +289,7 @@ Found 2 errors in the same file, starting at: a.ts:3 "category": 1, "messageKey": "_0_is_specified_more_than_once_so_this_usage_will_be_overwritten_2783", "messageArgs": [ - "�@iterator@" + "__@iterator@" ], "relatedInformation": [ { @@ -304,7 +304,7 @@ Found 2 errors in the same file, starting at: a.ts:3 ] ] ], - "size": 3854 + "size": 3853 } tsconfig.json:: @@ -329,7 +329,7 @@ Output:: 8 ...files,    ~~~~~~~~ -a.ts:5:5 - error TS2783: '�@iterator@' is specified more than once, so this usage will be overwritten. +a.ts:5:5 - error TS2783: '__@iterator@' is specified more than once, so this usage will be overwritten. 5 [Symbol.iterator]: function* (): IterableIterator {    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 958848b0365015750bd41f934e76ff6d88ebacea Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 22 Jul 2026 21:39:45 -0700 Subject: [PATCH 2/3] Remove redundant symbol name test --- internal/ast/symbol_test.go | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 internal/ast/symbol_test.go diff --git a/internal/ast/symbol_test.go b/internal/ast/symbol_test.go deleted file mode 100644 index 58f85605dfc..00000000000 --- a/internal/ast/symbol_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package ast_test - -import ( - "testing" - "unicode/utf8" - - "github.com/microsoft/typescript-go/internal/ast" - "github.com/microsoft/typescript-go/internal/json" - "gotest.tools/v3/assert" -) - -func TestSymbolNameEncoding(t *testing.T) { - t.Parallel() - - internalName := ast.InternalSymbolNameCall - userName := ast.EscapeLeadingUnderscores("__call") - - assert.Assert(t, utf8.ValidString(string(internalName))) - assert.Assert(t, internalName != userName) - assert.Equal(t, internalName.EscapedText(), "__call") - assert.Equal(t, userName.EscapedText(), "___call") - assert.Equal(t, ast.UnescapeLeadingUnderscores(userName), "__call") - - encoded, err := json.Marshal([]ast.SymbolNameKey{internalName, userName}) - assert.NilError(t, err) - var decoded []string - assert.NilError(t, json.Unmarshal(encoded, &decoded)) - assert.DeepEqual(t, decoded, []string{string(internalName), string(userName)}) -} From 55d737f6e4b81457d7cbb3ba136ab47005577ebc Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:05:23 -0700 Subject: [PATCH 3/3] Clean up symbol name key migration --- internal/ast/ast.go | 2 +- internal/binder/binder.go | 13 +++---- internal/checker/checker.go | 4 +-- .../tests/signatureHelpAnonymousType_test.go | 11 ++++++ internal/ls/autoimport/export.go | 14 +++++--- internal/ls/autoimport/extract.go | 32 ++++++++--------- internal/ls/autoimport/extract_test.go | 15 ++++++++ internal/ls/autoimport/fix.go | 4 +-- internal/ls/completions.go | 6 ++-- internal/ls/signaturehelp.go | 3 +- .../signatureHelpLeadingUnderscores.baseline | 36 +++++++++++++++++++ 11 files changed, 101 insertions(+), 39 deletions(-) create mode 100644 internal/ls/autoimport/extract_test.go create mode 100644 testdata/baselines/reference/fourslash/signatureHelp/signatureHelpLeadingUnderscores.baseline diff --git a/internal/ast/ast.go b/internal/ast/ast.go index 6dcd606b57e..aa0dee1af49 100644 --- a/internal/ast/ast.go +++ b/internal/ast/ast.go @@ -2517,7 +2517,7 @@ type SourceFile struct { BindSuggestionDiagnostics []*Diagnostic EndFlowNode *FlowNode SymbolCount int - ClassifiableNames collections.Set[string] + ClassifiableNames collections.Set[SymbolNameKey] PatternAmbientModules []*PatternAmbientModule GlobalExports SymbolTable diff --git a/internal/binder/binder.go b/internal/binder/binder.go index a5cf60e4dad..6c434f0150d 100644 --- a/internal/binder/binder.go +++ b/internal/binder/binder.go @@ -73,7 +73,7 @@ type Binder struct { inAssignmentPattern bool seenParseError bool symbolCount int - classifiableNames collections.Set[string] + classifiableNames collections.Set[ast.SymbolNameKey] notConstEnumOnlyModules collections.Set[*ast.Symbol] symbolArena core.Arena[ast.Symbol] flowNodeArena core.Arena[ast.FlowNode] @@ -193,7 +193,7 @@ func (b *Binder) declareSymbolEx(symbolTable ast.SymbolTable, parent *ast.Symbol // just add this node into the declarations list of the symbol. symbol = symbolTable[name] if includes&ast.SymbolFlagsClassifiable != 0 { - b.classifiableNames.Add(string(name)) + b.classifiableNames.Add(name) } if symbol == nil { symbol = b.newSymbol(ast.SymbolFlagsNone, name) @@ -305,10 +305,7 @@ func (b *Binder) declareSymbolEx(symbolTable ast.SymbolTable, parent *ast.Symbol // unless it is a well known Symbol. func (b *Binder) getDeclarationName(node *ast.Node) ast.SymbolNameKey { if ast.IsExportAssignment(node) { - if node.AsExportAssignment().IsExportEquals { - return ast.InternalSymbolNameExportEquals - } - return ast.InternalSymbolNameDefault + return core.IfElse(node.AsExportAssignment().IsExportEquals, ast.InternalSymbolNameExportEquals, ast.InternalSymbolNameDefault) } name := ast.GetNameOfDeclaration(node) if name != nil { @@ -369,7 +366,7 @@ func (b *Binder) getDisplayName(node *ast.Node) string { } name := b.getDeclarationName(node) if name != ast.InternalSymbolNameMissing { - return string(name) + return ast.UnescapeLeadingUnderscores(name) } return "(Missing)" } @@ -954,7 +951,7 @@ func (b *Binder) bindClassLikeDeclaration(node *ast.Node) { nameText := ast.InternalSymbolNameClass if name != nil { nameText = ast.EscapeLeadingUnderscores(name.Text()) - b.classifiableNames.Add(string(nameText)) + b.classifiableNames.Add(nameText) } b.bindAnonymousDeclaration(node, ast.SymbolFlagsClass, nameText) } diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 9e42dd0afc6..c60c745df96 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -18416,11 +18416,11 @@ func (w *WideningContext) getChildContext(propertyName ast.SymbolNameKey) *Widen func (c *Checker) getPropertiesOfContext(context *WideningContext) []*ast.Symbol { if context.resolvedProperties == nil { - var names collections.OrderedMap[string, *ast.Symbol] + var names collections.OrderedMap[ast.SymbolNameKey, *ast.Symbol] for _, t := range c.getSiblingsOfContext(context) { if isObjectLiteralType(t) && t.objectFlags&ObjectFlagsContainsSpread == 0 { for _, prop := range c.getPropertiesOfType(t) { - names.Set(ast.UnescapeLeadingUnderscores(prop.Name), prop) + names.Set(prop.Name, prop) } } } diff --git a/internal/fourslash/tests/signatureHelpAnonymousType_test.go b/internal/fourslash/tests/signatureHelpAnonymousType_test.go index a92e9f7f15e..d3006fc5d89 100644 --- a/internal/fourslash/tests/signatureHelpAnonymousType_test.go +++ b/internal/fourslash/tests/signatureHelpAnonymousType_test.go @@ -17,3 +17,14 @@ comparers.push((a,/**/ b) => true);` defer done() f.VerifyBaselineSignatureHelp(t) } + +func TestSignatureHelpLeadingUnderscores(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `function __foo(value: number) {} + +__foo(/*1*/);` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifyBaselineSignatureHelp(t) +} diff --git a/internal/ls/autoimport/export.go b/internal/ls/autoimport/export.go index 97f72d14f6c..f36e52d0fb1 100644 --- a/internal/ls/autoimport/export.go +++ b/internal/ls/autoimport/export.go @@ -19,7 +19,7 @@ type ModuleID string type ExportID struct { ModuleID ModuleID - ExportName string + ExportName ast.SymbolNameKey } type ExportSyntax int @@ -54,7 +54,7 @@ type Export struct { localName string // through is the name of the module symbol's export that this export was found on, // either 'export=', InternalSymbolNameExportStar, or empty string. - through string + through ast.SymbolNameKey // Checker-set fields @@ -70,17 +70,21 @@ type Export struct { } func (e *Export) Name() string { + return ast.UnescapeLeadingUnderscores(e.NameKey()) +} + +func (e *Export) NameKey() ast.SymbolNameKey { if e.localName != "" { - return e.localName + return ast.EscapeLeadingUnderscores(e.localName) } - if ast.EscapeLeadingUnderscores(e.ExportName) == ast.InternalSymbolNameExportEquals { + if e.ExportName == ast.InternalSymbolNameExportEquals { return e.Target.ExportName } return e.ExportName } func (e *Export) IsRenameable() bool { - return ast.EscapeLeadingUnderscores(e.ExportName) == ast.InternalSymbolNameExportEquals || ast.EscapeLeadingUnderscores(e.ExportName) == ast.InternalSymbolNameDefault + return e.ExportName == ast.InternalSymbolNameExportEquals || e.ExportName == ast.InternalSymbolNameDefault } func (e *Export) AmbientModuleName() string { diff --git a/internal/ls/autoimport/extract.go b/internal/ls/autoimport/extract.go index 19b13ee34d8..c8d6775c2ea 100644 --- a/internal/ls/autoimport/extract.go +++ b/internal/ls/autoimport/extract.go @@ -191,12 +191,12 @@ func (e *symbolExtractor) extractFromSymbol(name ast.SymbolNameKey, symbol *ast. if parent != nil && parent.IsExternalModule() { if targetModuleID, ok := e.getModuleIDForSymbol(parent); ok { export.Target = ExportID{ - ExportName: ast.UnescapeLeadingUnderscores(reexportedSymbol.Name), + ExportName: reexportedSymbol.Name, ModuleID: targetModuleID, } } } - export.through = ast.UnescapeLeadingUnderscores(ast.InternalSymbolNameExportStar) + export.through = ast.InternalSymbolNameExportStar *exports = append(*exports, export) } } @@ -219,7 +219,7 @@ func (e *symbolExtractor) extractFromSymbol(name ast.SymbolNameKey, symbol *ast. if innerName != ast.InternalSymbolNameExportStar { export, _ := e.createExport(namedExport, moduleID, moduleFileName, syntax, file, checkerLease) if export != nil { - export.through = ast.UnescapeLeadingUnderscores(name) + export.through = name *exports = append(*exports, export) } } @@ -236,7 +236,7 @@ func (e *symbolExtractor) extractFromSymbol(name ast.SymbolNameKey, symbol *ast. if ast.IsShorthandPropertyAssignment(prop) || ast.IsPropertyAssignment(prop) && prop.AsPropertyAssignment().Name().Kind == ast.KindIdentifier { export, _ := e.createExport(expression.Symbol().Members[ast.EscapeLeadingUnderscores(prop.Name().Text())], moduleID, moduleFileName, syntax, file, checkerLease) if export != nil { - export.through = ast.UnescapeLeadingUnderscores(name) + export.through = name *exports = append(*exports, export) } } @@ -253,7 +253,7 @@ func (e *symbolExtractor) createExport(symbol *ast.Symbol, moduleID ModuleID, mo export := &Export{ ExportID: ExportID{ - ExportName: ast.UnescapeLeadingUnderscores(symbol.Name), + ExportName: symbol.Name, ModuleID: moduleID, }, ModuleFileName: moduleFileName, @@ -264,7 +264,7 @@ func (e *symbolExtractor) createExport(symbol *ast.Symbol, moduleID ModuleID, mo } if syntax == ExportSyntaxUMD { - export.ExportName = ast.UnescapeLeadingUnderscores(ast.InternalSymbolNameExportEquals) + export.ExportName = ast.InternalSymbolNameExportEquals export.localName = ast.UnescapeLeadingUnderscores(symbol.Name) } @@ -306,7 +306,7 @@ func (e *symbolExtractor) createExport(symbol *ast.Symbol, moduleID ModuleID, mo } } export.Target = ExportID{ - ExportName: ast.UnescapeLeadingUnderscores(targetSymbol.Name), + ExportName: targetSymbol.Name, ModuleID: targetModuleID, } } @@ -321,10 +321,10 @@ func (e *symbolExtractor) createExport(symbol *ast.Symbol, moduleID ModuleID, mo namedSymbol = s } export.localName = getDefaultLikeExportNameFromDeclaration(namedSymbol) - if isUnusableName(export.localName) { - export.localName = export.Target.ExportName + if isUnusableName(ast.EscapeLeadingUnderscores(export.localName)) { + export.localName = ast.UnescapeLeadingUnderscores(export.Target.ExportName) } - if isUnusableName(export.localName) { + if isUnusableName(ast.EscapeLeadingUnderscores(export.localName)) { if targetSymbol != nil { namedSymbol = targetSymbol if s := binder.GetLocalSymbolForExportDefault(targetSymbol); s != nil { @@ -333,7 +333,7 @@ func (e *symbolExtractor) createExport(symbol *ast.Symbol, moduleID ModuleID, mo export.localName = getDefaultLikeExportNameFromDeclaration(namedSymbol) } } - if isUnusableName(export.localName) { + if isUnusableName(ast.EscapeLeadingUnderscores(export.localName)) { // Last resort: derive identifier from the file name. Use FileName() (original // casing) rather than ModuleID/Path() which is lowercased on case-insensitive // file systems, losing PascalCase. @@ -341,7 +341,7 @@ func (e *symbolExtractor) createExport(symbol *ast.Symbol, moduleID ModuleID, mo } } - if isUnusableName(export.Name()) { + if isUnusableName(export.NameKey()) { return nil, nil } @@ -435,12 +435,12 @@ func getSyntax(symbol *ast.Symbol) ExportSyntax { return ExportSyntaxNone } -func isUnusableName(name string) bool { +func isUnusableName(name ast.SymbolNameKey) bool { return name == "" || name == "_default" || - ast.EscapeLeadingUnderscores(name) == ast.InternalSymbolNameExportStar || - ast.EscapeLeadingUnderscores(name) == ast.InternalSymbolNameDefault || - ast.EscapeLeadingUnderscores(name) == ast.InternalSymbolNameExportEquals + name == ast.InternalSymbolNameExportStar || + name == ast.InternalSymbolNameDefault || + name == ast.InternalSymbolNameExportEquals } // fileNameForDefaultExportName returns the best file name to use when deriving diff --git a/internal/ls/autoimport/extract_test.go b/internal/ls/autoimport/extract_test.go new file mode 100644 index 00000000000..4c991b72fdc --- /dev/null +++ b/internal/ls/autoimport/extract_test.go @@ -0,0 +1,15 @@ +package autoimport + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/ast" + "gotest.tools/v3/assert" +) + +func TestIsUnusableNameDistinguishesInternalNames(t *testing.T) { + t.Parallel() + + assert.Assert(t, isUnusableName(ast.InternalSymbolNameExportStar)) + assert.Assert(t, !isUnusableName(ast.EscapeLeadingUnderscores("__export"))) +} diff --git a/internal/ls/autoimport/fix.go b/internal/ls/autoimport/fix.go index 482ebb4b5ce..4103cdc72b9 100644 --- a/internal/ls/autoimport/fix.go +++ b/internal/ls/autoimport/fix.go @@ -785,7 +785,7 @@ func getImportKind(importingFile *ast.SourceFile, export *Export, program *compi case ExportSyntaxDefaultModifier, ExportSyntaxDefaultDeclaration: return lsproto.ImportKindDefault case ExportSyntaxNamed: - if ast.EscapeLeadingUnderscores(export.ExportName) == ast.InternalSymbolNameDefault { + if export.ExportName == ast.InternalSymbolNameDefault { return lsproto.ImportKindDefault } fallthrough @@ -793,7 +793,7 @@ func getImportKind(importingFile *ast.SourceFile, export *Export, program *compi return lsproto.ImportKindNamed case ExportSyntaxEquals, ExportSyntaxCommonJSModuleExports, ExportSyntaxUMD: // export.Syntax will be ExportSyntaxEquals for named exports/properties of an export='s target. - if ast.EscapeLeadingUnderscores(export.ExportName) != ast.InternalSymbolNameExportEquals { + if export.ExportName != ast.InternalSymbolNameExportEquals { return lsproto.ImportKindNamed } // !!! cache this? diff --git a/internal/ls/completions.go b/internal/ls/completions.go index c99907b6b9c..28a4ecc1622 100644 --- a/internal/ls/completions.go +++ b/internal/ls/completions.go @@ -976,15 +976,15 @@ func (l *LanguageService) getCompletionData( members := getPropertiesForCompletion(containerExpectedType, typeChecker) existingMembers := getPropertiesForCompletion(containerActualType, typeChecker) - existingMemberNames := collections.Set[string]{} + existingMemberNames := collections.Set[ast.SymbolNameKey]{} for _, member := range existingMembers { - existingMemberNames.Add(ast.UnescapeLeadingUnderscores(member.Name)) + existingMemberNames.Add(member.Name) } symbols = append( symbols, core.Filter(members, func(member *ast.Symbol) bool { - return !existingMemberNames.Has(ast.UnescapeLeadingUnderscores(member.Name)) + return !existingMemberNames.Has(member.Name) })..., ) diff --git a/internal/ls/signaturehelp.go b/internal/ls/signaturehelp.go index 909f8b45d69..6f68e8de0ed 100644 --- a/internal/ls/signaturehelp.go +++ b/internal/ls/signaturehelp.go @@ -299,8 +299,7 @@ func (l *LanguageService) createSignatureHelpItems(ctx context.Context, candidat // "__type". There is no meaningful name to show, so render the signature with // no prefix (as we already do when there is no call target symbol) rather than // leaking the internal name. - if callTargetSymbol != nil && - !strings.HasPrefix(callTargetSymbol.Name.EscapedText(), ast.InternalSymbolNamePrefix) { + if callTargetSymbol != nil && callTargetSymbol.Name != ast.InternalSymbolNameType { if useFullPrefix { callTargetDisplayParts.WriteString(c.SymbolToStringEx(callTargetSymbol, sourceFile.AsNode(), ast.SymbolFlagsNone, checker.SymbolFormatFlagsUseAliasDefinedOutsideCurrentScope)) } else { diff --git a/testdata/baselines/reference/fourslash/signatureHelp/signatureHelpLeadingUnderscores.baseline b/testdata/baselines/reference/fourslash/signatureHelp/signatureHelpLeadingUnderscores.baseline new file mode 100644 index 00000000000..354802793d5 --- /dev/null +++ b/testdata/baselines/reference/fourslash/signatureHelp/signatureHelpLeadingUnderscores.baseline @@ -0,0 +1,36 @@ +// === SignatureHelp === +=== /signatureHelpLeadingUnderscores.ts === +// function __foo(value: number) {} +// +// __foo(); +// ^ +// | ---------------------------------------------------------------------- +// | __foo(**value: number**): void +// | ---------------------------------------------------------------------- +[ + { + "marker": { + "Position": 40, + "LSPosition": { + "line": 2, + "character": 6 + }, + "Name": "1", + "Data": {} + }, + "item": { + "signatures": [ + { + "label": "__foo(value: number): void", + "parameters": [ + { + "label": "value: number" + } + ], + "activeParameter": 0 + } + ], + "activeSignature": 0 + } + } +] \ No newline at end of file