From 66b4033efaf2ab9447f075777fa7592395a5948e Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 28 Oct 2025 14:53:40 -0700 Subject: [PATCH 1/3] Various fixes to Quick Info --- internal/ls/hover.go | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/internal/ls/hover.go b/internal/ls/hover.go index 12a3c547d3..7eb2e3ada5 100644 --- a/internal/ls/hover.go +++ b/internal/ls/hover.go @@ -129,6 +129,9 @@ func getQuickInfoAndDeclarationAtLocation(c *checker.Checker, symbol *ast.Symbol } } flags := symbol.Flags + if flags&ast.SymbolFlagsProperty != 0 && declaration != nil && ast.IsMethodDeclaration(declaration) { + flags = ast.SymbolFlagsMethod + } if flags&ast.SymbolFlagsType != 0 && (ast.IsPartOfTypeNode(node) || ast.IsTypeDeclarationName(node)) { // If the symbol has a type meaning and we're in a type context, remove value-only meanings flags &^= ast.SymbolFlagsVariable | ast.SymbolFlagsFunction @@ -165,7 +168,11 @@ func getQuickInfoAndDeclarationAtLocation(c *checker.Checker, symbol *ast.Symbol } b.WriteString(c.SymbolToStringEx(symbol, container, ast.SymbolFlagsNone, symbolFormatFlags)) b.WriteString(": ") - b.WriteString(c.TypeToStringEx(c.GetTypeOfSymbolAtLocation(symbol, node), container, typeFormatFlags)) + if callNode := getCallOrNewExpression(node); callNode != nil { + b.WriteString(c.SignatureToStringEx(c.GetResolvedSignature(callNode), container, typeFormatFlags|checker.TypeFormatFlagsWriteCallStyleSignature|checker.TypeFormatFlagsWriteTypeArgumentsOfSignature|checker.TypeFormatFlagsWriteArrowStyleSignature)) + } else { + b.WriteString(c.TypeToStringEx(c.GetTypeOfSymbolAtLocation(symbol, node), container, typeFormatFlags)) + } case flags&ast.SymbolFlagsEnumMember != 0: b.WriteString("(enum member) ") t := c.GetTypeOfSymbol(symbol) @@ -176,22 +183,26 @@ func getQuickInfoAndDeclarationAtLocation(c *checker.Checker, symbol *ast.Symbol } case flags&(ast.SymbolFlagsFunction|ast.SymbolFlagsMethod) != 0: signatures := getSignaturesAtLocation(c, symbol, checker.SignatureKindCall, node) - if len(signatures) == 1 && signatures[0].Declaration() != nil { - declaration = signatures[0].Declaration() + if len(signatures) == 1 { + if d := signatures[0].Declaration(); d != nil && d.Flags&ast.NodeFlagsJSDoc == 0 { + declaration = d + } } - prefix := core.IfElse(symbol.Flags&ast.SymbolFlagsMethod != 0, "(method) ", "function ") + prefix := core.IfElse(flags&ast.SymbolFlagsMethod != 0, "(method) ", "function ") writeSignatures(&b, c, signatures, container, prefix, symbol) case flags&ast.SymbolFlagsConstructor != 0: signatures := getSignaturesAtLocation(c, symbol.Parent, checker.SignatureKindConstruct, node) - if len(signatures) == 1 && signatures[0].Declaration() != nil { - declaration = signatures[0].Declaration() + if len(signatures) == 1 { + if d := signatures[0].Declaration(); d != nil && d.Flags&ast.NodeFlagsJSDoc == 0 { + declaration = d + } } writeSignatures(&b, c, signatures, container, "constructor ", symbol.Parent) case flags&(ast.SymbolFlagsClass|ast.SymbolFlagsInterface) != 0: if node.Kind == ast.KindThisKeyword || ast.IsThisInTypeQuery(node) { b.WriteString("this") } else { - b.WriteString(core.IfElse(symbol.Flags&ast.SymbolFlagsClass != 0, "class ", "interface ")) + b.WriteString(core.IfElse(flags&ast.SymbolFlagsClass != 0, "class ", "interface ")) b.WriteString(c.SymbolToStringEx(symbol, container, ast.SymbolFlagsNone, symbolFormatFlags)) params := c.GetDeclaredTypeOfSymbol(symbol).AsInterfaceType().LocalTypeParameters() writeTypeParams(&b, c, params) @@ -288,7 +299,7 @@ func getCallOrNewExpression(node *ast.Node) *ast.Node { if ast.IsPropertyAccessExpression(node.Parent) && node.Parent.Name() == node { node = node.Parent } - if ast.IsCallExpression(node.Parent) || ast.IsNewExpression(node.Parent) { + if (ast.IsCallExpression(node.Parent) || ast.IsNewExpression(node.Parent)) && node.Parent.Expression() == node { return node.Parent } return nil From 94d32d703684fb148ad07f0b75ce0594191da682 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 28 Oct 2025 14:54:03 -0700 Subject: [PATCH 2/3] Accept new baselines --- .../quickInfoDisplayPartsConst.baseline | 8 ++++---- ...uickInfoDisplayPartsInterfaceMembers.baseline | 8 ++++---- .../quickInfo/quickInfoDisplayPartsLet.baseline | 8 ++++---- ...DisplayPartsTypeParameterInInterface.baseline | 16 ++++++++-------- .../quickInfo/quickInfoDisplayPartsVar.baseline | 8 ++++---- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsConst.baseline b/testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsConst.baseline index 4b083289a8..7ff8afba28 100644 --- a/testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsConst.baseline +++ b/testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsConst.baseline @@ -121,7 +121,7 @@ // ^ // | ---------------------------------------------------------------------- // | ```tsx -// | const h: { (a: string): number; (a: number): string; } +// | const h: (a: number) => string // | ``` // | // | ---------------------------------------------------------------------- @@ -129,7 +129,7 @@ // ^ // | ---------------------------------------------------------------------- // | ```tsx -// | const h: { (a: string): number; (a: number): string; } +// | const h: (a: string) => number // | ``` // | // | ---------------------------------------------------------------------- @@ -525,7 +525,7 @@ "item": { "contents": { "kind": "markdown", - "value": "```tsx\nconst h: { (a: string): number; (a: number): string; }\n```\n" + "value": "```tsx\nconst h: (a: number) => string\n```\n" }, "range": { "start": { @@ -552,7 +552,7 @@ "item": { "contents": { "kind": "markdown", - "value": "```tsx\nconst h: { (a: string): number; (a: number): string; }\n```\n" + "value": "```tsx\nconst h: (a: string) => number\n```\n" }, "range": { "start": { diff --git a/testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsInterfaceMembers.baseline b/testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsInterfaceMembers.baseline index 0008b74501..a6c509a4f2 100644 --- a/testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsInterfaceMembers.baseline +++ b/testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsInterfaceMembers.baseline @@ -54,7 +54,7 @@ // ^^^^^^^^^ // | ---------------------------------------------------------------------- // | ```tsx -// | var iInstance: I +// | var iInstance: () => string // | ``` // | // | ---------------------------------------------------------------------- @@ -69,7 +69,7 @@ // ^^^^^^^^^ // | ---------------------------------------------------------------------- // | ```tsx -// | var iInstance: I +// | var iInstance: () => I // | ``` // | // | ---------------------------------------------------------------------- @@ -249,7 +249,7 @@ "item": { "contents": { "kind": "markdown", - "value": "```tsx\nvar iInstance: I\n```\n" + "value": "```tsx\nvar iInstance: () => string\n```\n" }, "range": { "start": { @@ -303,7 +303,7 @@ "item": { "contents": { "kind": "markdown", - "value": "```tsx\nvar iInstance: I\n```\n" + "value": "```tsx\nvar iInstance: () => I\n```\n" }, "range": { "start": { diff --git a/testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsLet.baseline b/testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsLet.baseline index 720e49d93b..939ce26c55 100644 --- a/testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsLet.baseline +++ b/testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsLet.baseline @@ -121,7 +121,7 @@ // ^ // | ---------------------------------------------------------------------- // | ```tsx -// | let h: { (a: string): number; (a: number): string; } +// | let h: (a: number) => string // | ``` // | // | ---------------------------------------------------------------------- @@ -129,7 +129,7 @@ // ^ // | ---------------------------------------------------------------------- // | ```tsx -// | let h: { (a: string): number; (a: number): string; } +// | let h: (a: string) => number // | ``` // | // | ---------------------------------------------------------------------- @@ -525,7 +525,7 @@ "item": { "contents": { "kind": "markdown", - "value": "```tsx\nlet h: { (a: string): number; (a: number): string; }\n```\n" + "value": "```tsx\nlet h: (a: number) => string\n```\n" }, "range": { "start": { @@ -552,7 +552,7 @@ "item": { "contents": { "kind": "markdown", - "value": "```tsx\nlet h: { (a: string): number; (a: number): string; }\n```\n" + "value": "```tsx\nlet h: (a: string) => number\n```\n" }, "range": { "start": { diff --git a/testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsTypeParameterInInterface.baseline b/testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsTypeParameterInInterface.baseline index f318f084b2..5f6dcceb8c 100644 --- a/testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsTypeParameterInInterface.baseline +++ b/testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsTypeParameterInInterface.baseline @@ -171,7 +171,7 @@ // ^^^^ // | ---------------------------------------------------------------------- // | ```tsx -// | var iVal: I +// | var iVal: <"hello">(a: "hello", b: string) => "hello" // | ``` // | // | ---------------------------------------------------------------------- @@ -179,7 +179,7 @@ // ^^^^ // | ---------------------------------------------------------------------- // | ```tsx -// | var iVal: I +// | var iVal: <"hello">(a: "hello", b: string) => "hello" // | ``` // | // | ---------------------------------------------------------------------- @@ -404,7 +404,7 @@ // ^^^^^ // | ---------------------------------------------------------------------- // | ```tsx -// | var iVal1: I1> +// | var iVal1: >(a: I, b: I) => I // | ``` // | // | ---------------------------------------------------------------------- @@ -426,7 +426,7 @@ // ^^^^^ // | ---------------------------------------------------------------------- // | ```tsx -// | var iVal1: I1> +// | var iVal1: >(a: I, b: I) => I // | ``` // | // | ---------------------------------------------------------------------- @@ -1108,7 +1108,7 @@ "item": { "contents": { "kind": "markdown", - "value": "```tsx\nvar iVal: I\n```\n" + "value": "```tsx\nvar iVal: <\"hello\">(a: \"hello\", b: string) => \"hello\"\n```\n" }, "range": { "start": { @@ -1135,7 +1135,7 @@ "item": { "contents": { "kind": "markdown", - "value": "```tsx\nvar iVal: I\n```\n" + "value": "```tsx\nvar iVal: <\"hello\">(a: \"hello\", b: string) => \"hello\"\n```\n" }, "range": { "start": { @@ -1972,7 +1972,7 @@ "item": { "contents": { "kind": "markdown", - "value": "```tsx\nvar iVal1: I1>\n```\n" + "value": "```tsx\nvar iVal1: >(a: I, b: I) => I\n```\n" }, "range": { "start": { @@ -2053,7 +2053,7 @@ "item": { "contents": { "kind": "markdown", - "value": "```tsx\nvar iVal1: I1>\n```\n" + "value": "```tsx\nvar iVal1: >(a: I, b: I) => I\n```\n" }, "range": { "start": { diff --git a/testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsVar.baseline b/testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsVar.baseline index c5692ca6f2..a41312cf14 100644 --- a/testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsVar.baseline +++ b/testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsVar.baseline @@ -101,7 +101,7 @@ // ^ // | ---------------------------------------------------------------------- // | ```tsx -// | var h: { (a: string): number; (a: number): string; } +// | var h: (a: number) => string // | ``` // | // | ---------------------------------------------------------------------- @@ -109,7 +109,7 @@ // ^ // | ---------------------------------------------------------------------- // | ```tsx -// | var h: { (a: string): number; (a: number): string; } +// | var h: (a: string) => number // | ``` // | // | ---------------------------------------------------------------------- @@ -451,7 +451,7 @@ "item": { "contents": { "kind": "markdown", - "value": "```tsx\nvar h: { (a: string): number; (a: number): string; }\n```\n" + "value": "```tsx\nvar h: (a: number) => string\n```\n" }, "range": { "start": { @@ -478,7 +478,7 @@ "item": { "contents": { "kind": "markdown", - "value": "```tsx\nvar h: { (a: string): number; (a: number): string; }\n```\n" + "value": "```tsx\nvar h: (a: string) => number\n```\n" }, "range": { "start": { From dd239f1913ec52efa16a87767f1c485f6bab497e Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 28 Oct 2025 17:26:06 -0700 Subject: [PATCH 3/3] Include fixed fourslash tests --- internal/fourslash/_scripts/failingTests.txt | 3 --- ...completionListObjectMembersInTypeLocationWithTypeof_test.go | 2 +- .../tests/gen/getQuickInfoForIntersectionTypes_test.go | 2 +- .../quickInfoJsPropertyAssignedAfterMethodDeclaration_test.go | 2 +- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/internal/fourslash/_scripts/failingTests.txt b/internal/fourslash/_scripts/failingTests.txt index 2aba718e6e..29254c11a0 100644 --- a/internal/fourslash/_scripts/failingTests.txt +++ b/internal/fourslash/_scripts/failingTests.txt @@ -118,7 +118,6 @@ TestCompletionListInvalidMemberNames2 TestCompletionListInvalidMemberNames_escapeQuote TestCompletionListInvalidMemberNames_startWithSpace TestCompletionListInvalidMemberNames_withExistingIdentifier -TestCompletionListObjectMembersInTypeLocationWithTypeof TestCompletionListOfGenericSymbol TestCompletionListOnAliases TestCompletionListStringParenthesizedExpression @@ -251,7 +250,6 @@ TestGetJavaScriptQuickInfo7 TestGetJavaScriptQuickInfo8 TestGetJavaScriptSyntacticDiagnostics24 TestGetOccurrencesIfElseBroken -TestGetQuickInfoForIntersectionTypes TestHoverOverComment TestImportCompletionsPackageJsonExportsSpecifierEndsInTs TestImportCompletionsPackageJsonExportsTrailingSlash1 @@ -425,7 +423,6 @@ TestQuickInfoJSDocFunctionThis TestQuickInfoJSExport TestQuickInfoJsDocGetterSetterNoCrash1 TestQuickInfoJsDocNonDiscriminatedUnionSharedProp -TestQuickInfoJsPropertyAssignedAfterMethodDeclaration TestQuickInfoJsdocTypedefMissingType TestQuickInfoMappedSpreadTypes TestQuickInfoMappedType diff --git a/internal/fourslash/tests/gen/completionListObjectMembersInTypeLocationWithTypeof_test.go b/internal/fourslash/tests/gen/completionListObjectMembersInTypeLocationWithTypeof_test.go index 18576a0bff..7c1baea148 100644 --- a/internal/fourslash/tests/gen/completionListObjectMembersInTypeLocationWithTypeof_test.go +++ b/internal/fourslash/tests/gen/completionListObjectMembersInTypeLocationWithTypeof_test.go @@ -11,7 +11,7 @@ import ( func TestCompletionListObjectMembersInTypeLocationWithTypeof(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @strict: true const languageService = { getCompletions() {} } diff --git a/internal/fourslash/tests/gen/getQuickInfoForIntersectionTypes_test.go b/internal/fourslash/tests/gen/getQuickInfoForIntersectionTypes_test.go index d3d68ddc6b..fb71b8925f 100644 --- a/internal/fourslash/tests/gen/getQuickInfoForIntersectionTypes_test.go +++ b/internal/fourslash/tests/gen/getQuickInfoForIntersectionTypes_test.go @@ -9,7 +9,7 @@ import ( func TestGetQuickInfoForIntersectionTypes(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `function f(): string & {(): any} { return {}; diff --git a/internal/fourslash/tests/gen/quickInfoJsPropertyAssignedAfterMethodDeclaration_test.go b/internal/fourslash/tests/gen/quickInfoJsPropertyAssignedAfterMethodDeclaration_test.go index fec1804e5b..44bde5ac76 100644 --- a/internal/fourslash/tests/gen/quickInfoJsPropertyAssignedAfterMethodDeclaration_test.go +++ b/internal/fourslash/tests/gen/quickInfoJsPropertyAssignedAfterMethodDeclaration_test.go @@ -9,7 +9,7 @@ import ( func TestQuickInfoJsPropertyAssignedAfterMethodDeclaration(t *testing.T) { t.Parallel() - t.Skip() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") const content = `// @noLib: true // @allowJs: true