typescript-go icon indicating copy to clipboard operation
typescript-go copied to clipboard

Fix nil pointer dereference in completion at property start after JSDoc

Open Copilot opened this issue 3 weeks ago • 2 comments

Requesting completions at the beginning of a property name preceded by JSDoc caused a nil pointer panic when accessing contextToken.Kind.

Root Causes

  1. Variable shadowing in getRelevantTokens: Used := instead of =, creating a local variable that shadowed the return parameter, causing contextToken to return nil.

  2. Missing nil check in tryGetObjectTypeDeclarationCompletionContainer: The function could return a non-nil declaration even when contextToken was nil (specifically in the KindIdentifier case when isFromObjectTypeDeclaration(location) is true), leading to a crash when the caller tried to access contextToken.Kind.

Changes

  • Fixed variable shadowing in getRelevantTokens (line 2756) by changing contextToken := to contextToken = to properly assign to the return parameter
  • Added nil check in tryGetObjectTypeDeclarationCompletionContainer (line 4166) by adding contextToken != nil && condition before isFromObjectTypeDeclaration(location)
  • Added test TestCompletionJSDocBeforePropertyNoCrash to verify the crash is fixed
// Before: shadows the return parameter
contextToken := astnav.FindPrecedingToken(file, previousToken.Pos())

// After: assigns to return parameter
contextToken = astnav.FindPrecedingToken(file, previousToken.Pos())
// Before: could return declaration when contextToken is nil
if isFromObjectTypeDeclaration(location) {
    return ast.FindAncestor(location, ast.IsObjectTypeDeclaration)
}

// After: prevents returning declaration when contextToken is nil
if contextToken != nil && isFromObjectTypeDeclaration(location) {
    return ast.FindAncestor(location, ast.IsObjectTypeDeclaration)
}

Testing

  • ✅ Added test that reproduces the original crash scenario
  • ✅ All completion tests pass (25+ tests)
  • ✅ All fourslash tests pass (100+ tests)

The fixes ensure contextToken is correctly set and prevent accessing it when nil, resolving the crash while maintaining correct completion behavior.

Original prompt

This section details on the original issue you should resolve

<issue_title>Crash completing beginning of property name when preceded by JSDoc</issue_title> <issue_description>```ts export class SomeInterface { /** ruh-roh! / /$1*/property: string; }

export class SomeClass { /** ruh-roh! / /$2*/property = "value"; }


Request completions at the beginning of either property (markers `/*$1*/` and `/*$2*/`).

error] panic handling requesttextDocument/completionruntime error: invalid memory address or nil pointer dereferencegoroutine 23769 [running]: runtime/debug.Stack() runtime/debug/stack.go:26 +0x5e github.com/microsoft/typescript-go/internal/lsp.(*Server).recover(0xc0001e4008, 0xc026483a10) github.com/microsoft/typescript-go/internal/lsp/server.go:872 +0x58 panic({0xbddea0?, 0x16c8b70?}) runtime/panic.go:783 +0x132 github.com/microsoft/typescript-go/internal/ls.(*LanguageService).getCompletionData.func15() github.com/microsoft/typescript-go/internal/ls/completions.go:1447 +0xba github.com/microsoft/typescript-go/internal/ls.(*LanguageService).getCompletionData.func18(...) github.com/microsoft/typescript-go/internal/ls/completions.go:1689 github.com/microsoft/typescript-go/internal/ls.(*LanguageService).getCompletionData(0xc029141380, {0x107d088, 0xc029141320}, 0xc036d90008, 0xc005362f08, 0x85, 0xc0097e1e00) github.com/microsoft/typescript-go/internal/ls/completions.go:1717 +0x1edf github.com/microsoft/typescript-go/internal/ls.(*LanguageService).getCompletionsAtPosition(0xc029141380, {0x107d088, 0xc029141320}, 0xc005362f08, 0x85, 0x0) github.com/microsoft/typescript-go/internal/ls/completions.go:383 +0x2cf github.com/microsoft/typescript-go/internal/ls.(*LanguageService).ProvideCompletion(0xc029141380, {0x107d088, 0xc029141320}, {0xc0035e8690?, 0xc029141320?}, {0x35e8690?, 0xc0?}, 0xc02b74b0f0) github.com/microsoft/typescript-go/internal/ls/completions.go:44 +0xc8 github.com/microsoft/typescript-go/internal/lsp.(*Server).handleCompletion(0xc00140c008?, {0x107d088?, 0xc029141320?}, 0xc0035e8690?, 0x40b92c?) github.com/microsoft/typescript-go/internal/lsp/server.go:1208 +0x39 github.com/microsoft/typescript-go/internal/lsp.init.func1.registerLanguageServiceDocumentRequestHandler[...].16({0x107d088, 0xc029141320}, 0xc026483a10) github.com/microsoft/typescript-go/internal/lsp/server.go:621 +0x130 github.com/microsoft/typescript-go/internal/lsp.(*Server).handleRequestOrNotification(0xc0001e4008, {0x107d0c0?, 0xc01d1484b0?}, 0xc026483a10) github.com/microsoft/typescript-go/internal/lsp/server.go:502 +0x14b github.com/microsoft/typescript-go/internal/lsp.(*Server).dispatchLoop.func1() github.com/microsoft/typescript-go/internal/lsp/server.go:405 +0x3a created by github.com/microsoft/typescript-go/internal/lsp.(*Server).dispatchLoop in goroutine 10 github.com/microsoft/typescript-go/internal/lsp/server.go:425 +0x9ad


## Comments on the Issue (you are @copilot in this section)

<comments>
</comments>

  • Fixes microsoft/typescript-go#2253

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot avatar Dec 06 '25 17:12 Copilot