Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions internal/bundled/embed.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ func libPath() string {
return scheme + "libs"
}

func IsBundled(path string) bool {
_, ok := splitPath(path)
return ok
}

// wrappedFS is implemented directly rather than going through [io/fs.FS].
// Our vfs.FS works with file contents in terms of strings, and that's
// what go:embed does under the hood, but going through fs.FS will cause
Expand Down
4 changes: 4 additions & 0 deletions internal/bundled/noembed.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,7 @@ var libPath = sync.OnceValue(func() string {

return dir
})

func IsBundled(path string) bool {
return false
}
13 changes: 11 additions & 2 deletions internal/checker/nodebuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,19 @@ func (b *NodeBuilder) TypeToTypeNode(typ *Type, enclosingDeclaration *ast.Node,
// var _ NodeBuilderInterface = NewNodeBuilderAPI(nil, nil)

func NewNodeBuilder(ch *Checker, e *printer.EmitContext) *NodeBuilder {
impl := newNodeBuilderImpl(ch, e)
return NewNodeBuilderEx(ch, e, nil /*idToSymbol*/)
}

func NewNodeBuilderEx(ch *Checker, e *printer.EmitContext, idToSymbol map[*ast.IdentifierNode]*ast.Symbol) *NodeBuilder {
impl := newNodeBuilderImpl(ch, e, idToSymbol)
return &NodeBuilder{impl: impl, ctxStack: make([]*NodeBuilderContext, 0, 1), basicHost: ch.program}
}

func (c *Checker) getNodeBuilder() *NodeBuilder {
return NewNodeBuilder(c, printer.NewEmitContext())
return c.getNodeBuilderEx(nil /*idToSymbol*/)
}

func (c *Checker) getNodeBuilderEx(idToSymbol map[*ast.IdentifierNode]*ast.Symbol) *NodeBuilder {
b := NewNodeBuilderEx(c, printer.NewEmitContext(), idToSymbol)
return b
}
66 changes: 47 additions & 19 deletions internal/checker/nodebuilderimpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ type NodeBuilderImpl struct {

// reusable visitor
cloneBindingNameVisitor *ast.NodeVisitor

// symbols for synthesized identifiers, needed for e.g. inlay hints
idToSymbol map[*ast.IdentifierNode]*ast.Symbol
}

const (
Expand All @@ -107,8 +110,11 @@ const (

// Node builder utility functions

func newNodeBuilderImpl(ch *Checker, e *printer.EmitContext) *NodeBuilderImpl {
b := &NodeBuilderImpl{f: e.Factory.AsNodeFactory(), ch: ch, e: e}
func newNodeBuilderImpl(ch *Checker, e *printer.EmitContext, idToSymbol map[*ast.IdentifierNode]*ast.Symbol) *NodeBuilderImpl {
if idToSymbol == nil {
idToSymbol = make(map[*ast.IdentifierNode]*ast.Symbol)
}
b := &NodeBuilderImpl{f: e.Factory.AsNodeFactory(), ch: ch, e: e, idToSymbol: idToSymbol}
b.cloneBindingNameVisitor = ast.NewNodeVisitor(b.cloneBindingName, b.f, ast.NodeVisitorHooks{})
return b
}
Expand Down Expand Up @@ -482,7 +488,7 @@ func (b *NodeBuilderImpl) createEntityNameFromSymbolChain(chain []*ast.Symbol, i
b.ctx.flags ^= nodebuilder.FlagsInInitialEntityName
}

identifier := b.f.NewIdentifier(symbolName)
identifier := b.newIdentifier(symbolName, symbol)
b.e.AddEmitFlags(identifier, printer.EFNoAsciiEscaping)
// !!! TODO: smuggle type arguments out
// if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray<TypeNode | TypeParameterDeclaration>(typeParameterNodes));
Expand All @@ -499,7 +505,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.f.NewIdentifier(symbol.Name)
identifier := b.newIdentifier(symbol.Name, symbol)
if symbol.Parent != nil {
return b.f.NewQualifiedName(b.symbolToEntityNameNode(symbol.Parent), identifier)
}
Expand Down Expand Up @@ -701,7 +707,7 @@ func (b *NodeBuilderImpl) createAccessFromSymbolChain(chain []*ast.Symbol, index
)
}

identifier := b.f.NewIdentifier(symbolName)
identifier := b.newIdentifier(symbolName, symbol)
b.e.AddEmitFlags(identifier, printer.EFNoAsciiEscaping)
// !!! TODO: smuggle type arguments out
// if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray<TypeNode | TypeParameterDeclaration>(typeParameterNodes));
Expand Down Expand Up @@ -740,7 +746,7 @@ func (b *NodeBuilderImpl) createExpressionFromSymbolChain(chain []*ast.Symbol, i
}

if index == 0 || canUsePropertyAccess(symbolName) {
identifier := b.f.NewIdentifier(symbolName)
identifier := b.newIdentifier(symbolName, symbol)
b.e.AddEmitFlags(identifier, printer.EFNoAsciiEscaping)
// !!! TODO: smuggle type arguments out
// if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray<TypeNode | TypeParameterDeclaration>(typeParameterNodes));
Expand All @@ -764,7 +770,7 @@ func (b *NodeBuilderImpl) createExpressionFromSymbolChain(chain []*ast.Symbol, i
expression = b.f.NewNumericLiteral(symbolName, ast.TokenFlagsNone)
}
if expression == nil {
expression = b.f.NewIdentifier(symbolName)
expression = b.newIdentifier(symbolName, symbol)
b.e.AddEmitFlags(expression, printer.EFNoAsciiEscaping)
// !!! TODO: smuggle type arguments out
// if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray<TypeNode | TypeParameterDeclaration>(typeParameterNodes));
Expand Down Expand Up @@ -1252,7 +1258,11 @@ func (b *NodeBuilderImpl) setTextRange(range_ *ast.Node, location *ast.Node) *as
return range_
}
if !ast.NodeIsSynthesized(range_) || (range_.Flags&ast.NodeFlagsSynthesized == 0) || b.ctx.enclosingFile == nil || b.ctx.enclosingFile != ast.GetSourceFileOfNode(b.e.MostOriginal(range_)) {
original := range_
range_ = range_.Clone(b.f) // if `range` is synthesized or originates in another file, copy it so it definitely has synthetic positions
if symbol, ok := b.idToSymbol[original]; ok {
b.idToSymbol[range_] = symbol
}
}
if range_ == location || location == nil {
return range_
Expand Down Expand Up @@ -1327,7 +1337,7 @@ func (b *NodeBuilderImpl) typeParameterToName(typeParameter *Type) *ast.Identifi
if text != rawText {
// !!! TODO: smuggle type arguments out
// const typeArguments = getIdentifierTypeArguments(result);
result = b.f.NewIdentifier(text)
result = b.newIdentifier(text, typeParameter.symbol)
// setIdentifierTypeArguments(result, typeArguments);
}

Expand Down Expand Up @@ -1584,18 +1594,20 @@ 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.f.NewIdentifier(parameterSymbol.Name)
return b.newIdentifier(parameterSymbol.Name, parameterSymbol)
}

name := parameterDeclaration.Name()
switch name.Kind {
case ast.KindIdentifier:
cloned := b.f.DeepCloneNode(name)
b.e.SetEmitFlags(cloned, printer.EFNoAsciiEscaping)
b.idToSymbol[cloned] = parameterSymbol
return cloned
case ast.KindQualifiedName:
cloned := b.f.DeepCloneNode(name.AsQualifiedName().Right)
b.e.SetEmitFlags(cloned, printer.EFNoAsciiEscaping)
b.idToSymbol[cloned] = parameterSymbol
return cloned
default:
return b.cloneBindingName(name)
Expand Down Expand Up @@ -1667,7 +1679,7 @@ func (b *NodeBuilderImpl) typePredicateToTypePredicateNodeHelper(typePredicate *
}
var parameterName *ast.Node
if typePredicate.kind == TypePredicateKindIdentifier || typePredicate.kind == TypePredicateKindAssertsIdentifier {
parameterName = b.f.NewIdentifier(typePredicate.parameterName)
parameterName = b.newIdentifier(typePredicate.parameterName, nil /*symbol*/)
b.e.SetEmitFlags(parameterName, printer.EFNoAsciiEscaping)
} else {
parameterName = b.f.NewThisTypeNode()
Expand Down Expand Up @@ -1950,7 +1962,7 @@ func (b *NodeBuilderImpl) indexInfoToIndexSignatureDeclarationHelper(indexInfo *
name := getNameFromIndexInfo(indexInfo)
indexerTypeNode := b.typeToTypeNode(indexInfo.keyType)

indexingParameter := b.f.NewParameterDeclaration(nil, nil, b.f.NewIdentifier(name), nil, indexerTypeNode, nil)
indexingParameter := b.f.NewParameterDeclaration(nil, nil, b.newIdentifier(name, nil /*symbol*/), nil, indexerTypeNode, nil)
if typeNode == nil {
if indexInfo.valueType == nil {
typeNode = b.f.NewKeywordTypeNode(ast.KindAnyKeyword)
Expand Down Expand Up @@ -2082,10 +2094,10 @@ func (b *NodeBuilderImpl) trackComputedName(accessExpression *ast.Node, enclosin
}
}

func (b *NodeBuilderImpl) createPropertyNameNodeForIdentifierOrLiteral(name string, singleQuote bool, stringNamed bool, isMethod bool) *ast.Node {
func (b *NodeBuilderImpl) createPropertyNameNodeForIdentifierOrLiteral(name string, singleQuote bool, stringNamed bool, isMethod bool, symbol *ast.Symbol) *ast.Node {
isMethodNamedNew := isMethod && name == "new"
if !isMethodNamedNew && scanner.IsIdentifierText(name, core.LanguageVariantStandard) {
return b.f.NewIdentifier(name)
return b.newIdentifier(name, symbol)
}
if !stringNamed && !isMethodNamedNew && isNumericLiteralName(name) && jsnum.FromString(name) >= 0 {
return b.f.NewNumericLiteral(name, ast.TokenFlagsNone)
Expand Down Expand Up @@ -2133,7 +2145,7 @@ func (b *NodeBuilderImpl) getPropertyNameNodeForSymbol(symbol *ast.Symbol) *ast.
name = "__#private" + name
}

return b.createPropertyNameNodeForIdentifierOrLiteral(name, singleQuote, stringNamed, isMethod)
return b.createPropertyNameNodeForIdentifierOrLiteral(name, singleQuote, stringNamed, isMethod, symbol)
}

// See getNameForSymbolFromNameType for a stringy equivalent
Expand All @@ -2160,7 +2172,7 @@ func (b *NodeBuilderImpl) getPropertyNameNodeForSymbolFromNameType(symbol *ast.S
if isNumericLiteralName(name) && name[0] == '-' {
return b.f.NewComputedPropertyName(b.f.NewPrefixUnaryExpression(ast.KindMinusToken, b.f.NewNumericLiteral(name[1:], ast.TokenFlagsNone)))
}
return b.createPropertyNameNodeForIdentifierOrLiteral(name, singleQuote, stringNamed, isMethod)
return b.createPropertyNameNodeForIdentifierOrLiteral(name, singleQuote, stringNamed, isMethod, symbol)
}
if nameType.flags&TypeFlagsUniqueESSymbol != 0 {
return b.f.NewComputedPropertyName(b.symbolToExpression(nameType.AsUniqueESSymbolType().symbol, ast.SymbolFlagsValue))
Expand Down Expand Up @@ -2596,7 +2608,10 @@ func (b *NodeBuilderImpl) typeReferenceToTypeNode(t *Type) *ast.TypeNode {
if t.Target() == b.ch.globalArrayType || t.Target() == b.ch.globalReadonlyArrayType {
if b.ctx.flags&nodebuilder.FlagsWriteArrayAsGenericType != 0 {
typeArgumentNode := b.typeToTypeNode(typeArguments[0])
return b.f.NewTypeReferenceNode(b.f.NewIdentifier(core.IfElse(t.Target() == b.ch.globalArrayType, "Array", "ReadonlyArray")), b.f.NewNodeList([]*ast.TypeNode{typeArgumentNode}))
return b.f.NewTypeReferenceNode(
b.newIdentifier(core.IfElse(t.Target() == b.ch.globalArrayType, "Array", "ReadonlyArray"), t.Target().symbol),
b.f.NewNodeList([]*ast.TypeNode{typeArgumentNode}),
)
}
elementType := b.typeToTypeNode(typeArguments[0])
arrayType := b.f.NewArrayTypeNode(elementType)
Expand All @@ -2622,7 +2637,12 @@ func (b *NodeBuilderImpl) typeReferenceToTypeNode(t *Type) *ast.TypeNode {
labeledElementDeclaration := t.Target().AsTupleType().elementInfos[i].labeledDeclaration

if labeledElementDeclaration != nil {
tupleConstituentNodes.Nodes[i] = b.f.NewNamedTupleMember(core.IfElse(flags&ElementFlagsVariable != 0, b.f.NewToken(ast.KindDotDotDotToken), nil), b.f.NewIdentifier(b.ch.getTupleElementLabel(t.Target().AsTupleType().elementInfos[i], nil, i)), core.IfElse(flags&ElementFlagsOptional != 0, b.f.NewToken(ast.KindQuestionToken), nil), core.IfElse(flags&ElementFlagsRest != 0, b.f.NewArrayTypeNode(tupleConstituentNodes.Nodes[i]), tupleConstituentNodes.Nodes[i]))
tupleConstituentNodes.Nodes[i] = b.f.NewNamedTupleMember(
core.IfElse(flags&ElementFlagsVariable != 0, b.f.NewToken(ast.KindDotDotDotToken), nil),
b.newIdentifier(b.ch.getTupleElementLabel(t.Target().AsTupleType().elementInfos[i], nil, i), nil /*symbol*/),
core.IfElse(flags&ElementFlagsOptional != 0, b.f.NewToken(ast.KindQuestionToken), nil),
core.IfElse(flags&ElementFlagsRest != 0, b.f.NewArrayTypeNode(tupleConstituentNodes.Nodes[i]), tupleConstituentNodes.Nodes[i]),
)
} else {
switch {
case flags&ElementFlagsVariable != 0:
Expand Down Expand Up @@ -2997,7 +3017,7 @@ func (b *NodeBuilderImpl) typeToTypeNode(t *Type) *ast.TypeNode {
if b.ctx.flags&nodebuilder.FlagsGenerateNamesForShadowedTypeParams != 0 && t.flags&TypeFlagsTypeParameter != 0 {
name := b.typeParameterToName(t)
b.ctx.approximateLength += len(name.Text)
return b.f.NewTypeReferenceNode(b.f.NewIdentifier(name.Text), nil /*typeArguments*/)
return b.f.NewTypeReferenceNode(b.newIdentifier(name.Text, t.symbol), nil /*typeArguments*/)
}
// Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter.
if t.symbol != nil {
Expand All @@ -3009,7 +3029,7 @@ func (b *NodeBuilderImpl) typeToTypeNode(t *Type) *ast.TypeNode {
} else {
name = "?"
}
return b.f.NewTypeReferenceNode(b.f.NewIdentifier(name), nil /*typeArguments*/)
return b.f.NewTypeReferenceNode(b.newIdentifier(name, nil /*symbol*/), nil /*typeArguments*/)
}
if t.flags&TypeFlagsUnion != 0 && t.AsUnionType().origin != nil {
t = t.AsUnionType().origin
Expand Down Expand Up @@ -3113,3 +3133,11 @@ func (b *NodeBuilderImpl) newStringLiteralEx(text string, isSingleQuote bool) *a
func (t *TypeAlias) ToTypeReferenceNode(b *NodeBuilderImpl) *ast.Node {
return b.f.NewTypeReferenceNode(b.symbolToEntityNameNode(t.Symbol()), b.mapToTypeNodes(t.TypeArguments(), false /*isBareList*/))
}

func (b *NodeBuilderImpl) newIdentifier(text string, symbol *ast.Symbol) *ast.Node {
id := b.f.NewIdentifier(text)
if symbol != nil {
b.idToSymbol[id] = symbol
}
return id
}
8 changes: 4 additions & 4 deletions internal/checker/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,12 +373,12 @@ func (c *Checker) formatUnionTypes(types []*Type) []*Type {
return result
}

func (c *Checker) TypeToTypeNode(t *Type, enclosingDeclaration *ast.Node, flags nodebuilder.Flags) *ast.TypeNode {
nodeBuilder := c.getNodeBuilder()
func (c *Checker) TypeToTypeNode(t *Type, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, idToSymbol map[*ast.IdentifierNode]*ast.Symbol) *ast.TypeNode {
nodeBuilder := c.getNodeBuilderEx(idToSymbol)
return nodeBuilder.TypeToTypeNode(t, enclosingDeclaration, flags, nodebuilder.InternalFlagsNone, nil)
}

func (c *Checker) TypePredicateToTypePredicateNode(t *TypePredicate, enclosingDeclaration *ast.Node, flags nodebuilder.Flags) *ast.TypePredicateNodeNode {
nodeBuilder := c.getNodeBuilder()
func (c *Checker) TypePredicateToTypePredicateNode(t *TypePredicate, enclosingDeclaration *ast.Node, flags nodebuilder.Flags, idToSymbol map[*ast.IdentifierNode]*ast.Symbol) *ast.TypePredicateNodeNode {
nodeBuilder := c.getNodeBuilderEx(idToSymbol)
return nodeBuilder.TypePredicateToTypePredicateNode(t, enclosingDeclaration, flags, nodebuilder.InternalFlagsNone, nil)
}
3 changes: 2 additions & 1 deletion internal/fourslash/fourslash.go
Original file line number Diff line number Diff line change
Expand Up @@ -3450,12 +3450,13 @@ func (f *FourslashTest) VerifyBaselineInlayHints(
annotations = core.Map(*result.InlayHints, func(hint *lsproto.InlayHint) string {
if hint.Label.InlayHintLabelParts != nil {
for _, part := range *hint.Label.InlayHintLabelParts {
// Avoid diffs caused by lib file updates.
if part.Location != nil && isLibFile(part.Location.Uri.FileName()) {
part.Location.Range.Start = lsproto.Position{Line: 0, Character: 0}
part.Location.Range.End = lsproto.Position{Line: 0, Character: 0}
}
}
}

underline := strings.Repeat(" ", int(hint.Position.Character)) + "^"
hintJson, err := core.StringifyJson(hint, "", " ")
if err != nil {
Expand Down
20 changes: 20 additions & 0 deletions internal/fourslash/tests/inlayHintsIdentifierLocation_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package fourslash_test

import (
"testing"

"github.com/microsoft/typescript-go/internal/fourslash"
"github.com/microsoft/typescript-go/internal/ls/lsutil"
"github.com/microsoft/typescript-go/internal/testutil"
)

func TestInlayHintsIdentifierLocation(t *testing.T) {
fourslash.SkipIfFailing(t)
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `interface Foo {}
const p = (a: Foo[]) => a;`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyBaselineInlayHints(t, nil /*span*/, &lsutil.UserPreferences{InlayHints: lsutil.InlayHintsPreferences{IncludeInlayVariableTypeHints: true}})
}
21 changes: 6 additions & 15 deletions internal/ls/completions.go
Original file line number Diff line number Diff line change
Expand Up @@ -2483,20 +2483,6 @@ func strPtrTo(v string) *string {
return &v
}

func ptrIsTrue(ptr *bool) bool {
if ptr == nil {
return false
}
return *ptr
}

func ptrIsFalse(ptr *bool) bool {
if ptr == nil {
return false
}
return !*ptr
}

func boolToPtr(v bool) *bool {
if v {
return ptrTo(true)
Expand Down Expand Up @@ -5902,7 +5888,12 @@ func getJSDocParamAnnotation(
nodebuilder.FlagsUseSingleQuotesForStringLiteralType,
nodebuilder.FlagsNone,
)
typeNode := typeChecker.TypeToTypeNode(inferredType, ast.FindAncestor(initializer, ast.IsFunctionLike), builderFlags)
typeNode := typeChecker.TypeToTypeNode(
inferredType,
ast.FindAncestor(initializer, ast.IsFunctionLike),
builderFlags,
nil, /*idToSymbol*/
)
if typeNode != nil {
emitContext := printer.NewEmitContext()
// !!! snippet p
Expand Down
Loading