From a6bfa7bec3692c646270d7afdb631b3a7d55a02c Mon Sep 17 00:00:00 2001 From: gonappuccino Date: Fri, 25 Sep 2026 00:50:08 -0400 Subject: [PATCH 1/3] Report the member name instead of the signature in deprecation suggestions --- tsc/internal/checker/checker.go | 8 ++- .../deprecatedSignatureMemberName_test.go | 51 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 tsc/internal/fourslash/tests/deprecatedSignatureMemberName_test.go diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 983fc751b03f8..c175211ba9c3c 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -8539,7 +8539,13 @@ func (c *Checker) checkDeprecatedSignature(sig *Signature, node *ast.Node) { } if sig.declaration != nil && c.IsDeprecatedDeclaration(sig.declaration) { suggestionNode := c.getDeprecatedSuggestionNode(node) - name := tryGetPropertyAccessOrIdentifierToString(ast.GetInvokedExpression(node)) + invokedExpression := ast.GetInvokedExpression(node) + name := tryGetPropertyAccessOrIdentifierToString(invokedExpression) + if name == "" && ast.IsAccessExpression(invokedExpression) { + if memberName := ast.GetElementOrPropertyAccessName(invokedExpression); memberName != nil { + name = memberName.Text() + } + } c.addDeprecatedSuggestionWithSignature(suggestionNode, sig.declaration, name, c.signatureToString(sig)) } } diff --git a/tsc/internal/fourslash/tests/deprecatedSignatureMemberName_test.go b/tsc/internal/fourslash/tests/deprecatedSignatureMemberName_test.go new file mode 100644 index 0000000000000..086aa8f426d5b --- /dev/null +++ b/tsc/internal/fourslash/tests/deprecatedSignatureMemberName_test.go @@ -0,0 +1,51 @@ +package fourslash_test + +import ( + "testing" + + "github.com/microsoft/TypeScript/tsc/internal/fourslash" + "github.com/microsoft/TypeScript/tsc/internal/lsp/lsproto" + "github.com/microsoft/TypeScript/tsc/internal/testutil" +) + +func TestDeprecatedSignatureMemberName(t *testing.T) { + t.Parallel() + defer testutil.RecoverAndFail(t, "Panic on fourslash test") + const content = `// @filename: /a.ts +interface Schema { + /** @deprecated */ + passthrough(): Schema; +} +declare function object(): Schema; +object().[|passthrough|](); +object()[[|"passthrough"|]](); +class C { + /** @deprecated */ + m() {} + n() { + this.[|m|](); + } +}` + f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) + defer done() + f.VerifySuggestionDiagnostics(t, []*lsproto.Diagnostic{ + { + Code: &lsproto.IntegerOrString{Integer: new(int32(6387))}, + Message: lsproto.StringOrMarkupContent{String: new("The signature '(): Schema' of 'passthrough' is deprecated.")}, + Tags: &[]lsproto.DiagnosticTag{lsproto.DiagnosticTagDeprecated}, + Range: f.Ranges()[0].LSRange, + }, + { + Code: &lsproto.IntegerOrString{Integer: new(int32(6387))}, + Message: lsproto.StringOrMarkupContent{String: new("The signature '(): Schema' of 'passthrough' is deprecated.")}, + Tags: &[]lsproto.DiagnosticTag{lsproto.DiagnosticTagDeprecated}, + Range: f.Ranges()[1].LSRange, + }, + { + Code: &lsproto.IntegerOrString{Integer: new(int32(6387))}, + Message: lsproto.StringOrMarkupContent{String: new("The signature '(): void' of 'm' is deprecated.")}, + Tags: &[]lsproto.DiagnosticTag{lsproto.DiagnosticTagDeprecated}, + Range: f.Ranges()[2].LSRange, + }, + }) +} From 275af7e1adcbb876c345036bc350c3fe89ad136f Mon Sep 17 00:00:00 2001 From: gonappuccino Date: Fri, 25 Sep 2026 01:04:03 -0400 Subject: [PATCH 2/3] Also report private member names in deprecation suggestions --- tsc/internal/checker/checker.go | 11 ++++++++--- .../tests/deprecatedSignatureMemberName_test.go | 9 +++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index c175211ba9c3c..3a7a254a105b9 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -8541,9 +8541,14 @@ func (c *Checker) checkDeprecatedSignature(sig *Signature, node *ast.Node) { suggestionNode := c.getDeprecatedSuggestionNode(node) invokedExpression := ast.GetInvokedExpression(node) name := tryGetPropertyAccessOrIdentifierToString(invokedExpression) - if name == "" && ast.IsAccessExpression(invokedExpression) { - if memberName := ast.GetElementOrPropertyAccessName(invokedExpression); memberName != nil { - name = memberName.Text() + if name == "" { + switch { + case ast.IsPropertyAccessExpression(invokedExpression): + name = invokedExpression.Name().Text() + case ast.IsElementAccessExpression(invokedExpression): + if memberName := ast.GetElementOrPropertyAccessName(invokedExpression); memberName != nil { + name = memberName.Text() + } } } c.addDeprecatedSuggestionWithSignature(suggestionNode, sig.declaration, name, c.signatureToString(sig)) diff --git a/tsc/internal/fourslash/tests/deprecatedSignatureMemberName_test.go b/tsc/internal/fourslash/tests/deprecatedSignatureMemberName_test.go index 086aa8f426d5b..316ea8770c86d 100644 --- a/tsc/internal/fourslash/tests/deprecatedSignatureMemberName_test.go +++ b/tsc/internal/fourslash/tests/deprecatedSignatureMemberName_test.go @@ -22,8 +22,11 @@ object()[[|"passthrough"|]](); class C { /** @deprecated */ m() {} + /** @deprecated */ + #p() {} n() { this.[|m|](); + this.[|#p|](); } }` f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content) @@ -47,5 +50,11 @@ class C { Tags: &[]lsproto.DiagnosticTag{lsproto.DiagnosticTagDeprecated}, Range: f.Ranges()[2].LSRange, }, + { + Code: &lsproto.IntegerOrString{Integer: new(int32(6387))}, + Message: lsproto.StringOrMarkupContent{String: new("The signature '(): void' of '#p' is deprecated.")}, + Tags: &[]lsproto.DiagnosticTag{lsproto.DiagnosticTagDeprecated}, + Range: f.Ranges()[3].LSRange, + }, }) } From 82012d3e7d0244f44917a9094525c6505009417a Mon Sep 17 00:00:00 2001 From: gonappuccino Date: Fri, 25 Sep 2026 01:27:34 -0400 Subject: [PATCH 3/3] Skip parentheses around the callee when naming a deprecated signature --- tsc/internal/checker/checker.go | 2 +- .../deprecatedSignatureMemberName_test.go | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 3a7a254a105b9..19b4ac83d6196 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -8539,7 +8539,7 @@ func (c *Checker) checkDeprecatedSignature(sig *Signature, node *ast.Node) { } if sig.declaration != nil && c.IsDeprecatedDeclaration(sig.declaration) { suggestionNode := c.getDeprecatedSuggestionNode(node) - invokedExpression := ast.GetInvokedExpression(node) + invokedExpression := ast.SkipParentheses(ast.GetInvokedExpression(node)) name := tryGetPropertyAccessOrIdentifierToString(invokedExpression) if name == "" { switch { diff --git a/tsc/internal/fourslash/tests/deprecatedSignatureMemberName_test.go b/tsc/internal/fourslash/tests/deprecatedSignatureMemberName_test.go index 316ea8770c86d..c456a9b777ef5 100644 --- a/tsc/internal/fourslash/tests/deprecatedSignatureMemberName_test.go +++ b/tsc/internal/fourslash/tests/deprecatedSignatureMemberName_test.go @@ -19,6 +19,7 @@ interface Schema { declare function object(): Schema; object().[|passthrough|](); object()[[|"passthrough"|]](); +(object().[|passthrough|])(); class C { /** @deprecated */ m() {} @@ -44,17 +45,30 @@ class C { Tags: &[]lsproto.DiagnosticTag{lsproto.DiagnosticTagDeprecated}, Range: f.Ranges()[1].LSRange, }, + // A parenthesized callee also reports the deprecated property itself; that suggestion is unchanged. + { + Code: &lsproto.IntegerOrString{Integer: new(int32(6385))}, + Message: lsproto.StringOrMarkupContent{String: new("'passthrough' is deprecated.")}, + Tags: &[]lsproto.DiagnosticTag{lsproto.DiagnosticTagDeprecated}, + Range: f.Ranges()[2].LSRange, + }, { Code: &lsproto.IntegerOrString{Integer: new(int32(6387))}, - Message: lsproto.StringOrMarkupContent{String: new("The signature '(): void' of 'm' is deprecated.")}, + Message: lsproto.StringOrMarkupContent{String: new("The signature '(): Schema' of 'passthrough' is deprecated.")}, Tags: &[]lsproto.DiagnosticTag{lsproto.DiagnosticTagDeprecated}, Range: f.Ranges()[2].LSRange, }, { Code: &lsproto.IntegerOrString{Integer: new(int32(6387))}, - Message: lsproto.StringOrMarkupContent{String: new("The signature '(): void' of '#p' is deprecated.")}, + Message: lsproto.StringOrMarkupContent{String: new("The signature '(): void' of 'm' is deprecated.")}, Tags: &[]lsproto.DiagnosticTag{lsproto.DiagnosticTagDeprecated}, Range: f.Ranges()[3].LSRange, }, + { + Code: &lsproto.IntegerOrString{Integer: new(int32(6387))}, + Message: lsproto.StringOrMarkupContent{String: new("The signature '(): void' of '#p' is deprecated.")}, + Tags: &[]lsproto.DiagnosticTag{lsproto.DiagnosticTagDeprecated}, + Range: f.Ranges()[4].LSRange, + }, }) }