Skip to content

Panic in no_unnecessary_type_assertion autofix with JSDoc cast on ParenthesizedExpression #5

@Jkker

Description

@Jkker

Bug Description

tsgolint panics with slice bounds out of range when running autofix on a redundant JSDoc type assertion that is applied to a parenthesized expression.

Reproduction

Create repro.js:

/** @type {string} */
const s = "foo";

// CRASHES: JSDoc cast on parenthesized expression
const s2 = /** @type {string} */ (s);

Run: oxlint --type-aware --fix repro.js

Differential Analysis

The panic is specific to JSDoc casts on parenthesized expressions. Other forms of assertions do NOT crash:

// OK: JSDoc cast inside parens
const s3 = (/** @type {string} */ s);

// OK: JSDoc cast without parens
const s4 = /** @type {string} */ s;

// OK: TypeScript 'as' syntax
// const s5 = (s as string);

// OK: TypeScript angle-bracket syntax
// const s6 = <string>s;

Stack Trace

panic: runtime error: slice bounds out of range [76:62]
goroutine 104 [running]:
github.com/typescript-eslint/tsgolint/internal/rules/no_unnecessary_type_assertion.init.func1.6.1()
	/home/runner/work/tsgolint/tsgolint/internal/rules/no_unnecessary_type_assertion/no_unnecessary_type_assertion.go:268 +0x225
github.com/typescript-eslint/tsgolint/internal/linter.RunLinterOnProgram.func2.4(0xc0036581c0, {{0xb87e31, 0x14}, {0xbbe2db, 0x52}, {0x0, 0x0}}, 0xc00011f920)
	/home/runner/work/tsgolint/tsgolint/internal/linter/linter.go:268 +0xb6
github.com/typescript-eslint/tsgolint/internal/rules/no_unnecessary_type_assertion.init.func1.6(0xc0036581c0)
	/home/runner/work/tsgolint/tsgolint/internal/rules/no_unnecessary_type_assertion/no_unnecessary_type_assertion.go:221 +0x4c4
github.com/typescript-eslint/tsgolint/internal/linter.RunLinterOnProgram.func2.6(0xeb, 0xc0036581c0)
	/home/runner/work/tsgolint/tsgolint/internal/linter/linter.go:303 +0x5f
github.com/typescript-eslint/tsgolint/internal/linter.RunLinterOnProgram.func2.8(0xc0036581c0)
	/home/runner/work/tsgolint/tsgolint/internal/linter/linter.go:350 +0x42
github.com/microsoft/typescript-go/internal/ast.visit(...)
	/home/runner/work/tsgolint/tsgolint/typescript-go/internal/ast/ast.go:22
github.com/microsoft/typescript-go/internal/ast.(*ParenthesizedExpression).ForEachChild(0x418574?, 0x4188c5?)
	/home/runner/work/tsgolint/tsgolint/typescript-go/internal/ast/ast.go:7229 +0x23
github.com/microsoft/typescript-go/internal/ast.(*Node).ForEachChild(0xda?, 0xc00365e0e0?)
	/home/runner/work/tsgolint/tsgolint/typescript-go/internal/ast/ast.go:243 +0x1c
github.com/typescript-eslint/tsgolint/internal/linter.RunLinterOnProgram.func2.8(0xc00365e0e0)
	/home/runner/work/tsgolint/tsgolint/internal/linter/linter.go:365 +0x125
github.com/microsoft/typescript-go/internal/ast.visit(...)
	/home/runner/work/tsgolint/tsgolint/typescript-go/internal/ast/ast.go:22
github.com/microsoft/typescript-go/internal/ast.(*VariableDeclaration).ForEachChild(0xc000f83318, 0xc000416f60)
	/home/runner/work/tsgolint/tsgolint/typescript-go/internal/ast/ast.go:3783 +0xc2
github.com/microsoft/typescript-go/internal/ast.(*Node).ForEachChild(0xc004760105?, 0xc000f83318?)
	/home/runner/work/tsgolint/tsgolint/typescript-go/internal/ast/ast.go:243 +0x1c
github.com/typescript-eslint/tsgolint/internal/linter.RunLinterOnProgram.func2.8(0xc000f83318)
	/home/runner/work/tsgolint/tsgolint/internal/linter/linter.go:365 +0x125
github.com/microsoft/typescript-go/internal/ast.visitNodes(...)
	/home/runner/work/tsgolint/tsgolint/typescript-go/internal/ast/ast.go:29
github.com/microsoft/typescript-go/internal/ast.visitNodeList(...)
	/home/runner/work/tsgolint/tsgolint/typescript-go/internal/ast/ast.go:38
github.com/microsoft/typescript-go/internal/ast.(*VariableDeclarationList).ForEachChild(0x0?, 0xc000416f60)
	/home/runner/work/tsgolint/tsgolint/typescript-go/internal/ast/ast.go:3833 +0x67
github.com/microsoft/typescript-go/internal/ast.(*Node).ForEachChild(0x106?, 0xc00362edc0?)
	/home/runner/work/tsgolint/tsgolint/typescript-go/internal/ast/ast.go:243 +0x1c
github.com/typescript-eslint/tsgolint/internal/linter.RunLinterOnProgram.func2.8(0xc00362edc0)
	/home/runner/work/tsgolint/tsgolint/internal/linter/linter.go:365 +0x125
github.com/microsoft/typescript-go/internal/ast.visit(...)
	/home/runner/work/tsgolint/tsgolint/typescript-go/internal/ast/ast.go:22
github.com/microsoft/typescript-go/internal/ast.(*VariableStatement).ForEachChild(0x418574?, 0xb845df?)
	/home/runner/work/tsgolint/tsgolint/typescript-go/internal/ast/ast.go:3729 +0x62
github.com/microsoft/typescript-go/internal/ast.(*Node).ForEachChild(0x4000f4?, 0xc003652410?)
	/home/runner/work/tsgolint/tsgolint/typescript-go/internal/ast/ast.go:243 +0x1c
github.com/typescript-eslint/tsgolint/internal/linter.RunLinterOnProgram.func2.8(0xc003652410)
	/home/runner/work/tsgolint/tsgolint/internal/linter/linter.go:365 +0x125
github.com/microsoft/typescript-go/internal/ast.visitNodes(...)
	/home/runner/work/tsgolint/tsgolint/typescript-go/internal/ast/ast.go:29
github.com/microsoft/typescript-go/internal/ast.visitNodeList(...)
	/home/runner/work/tsgolint/tsgolint/typescript-go/internal/ast/ast.go:38
github.com/microsoft/typescript-go/internal/ast.(*SourceFile).ForEachChild(0xc003623808, 0xc000416f60)
	/home/runner/work/tsgolint/tsgolint/typescript-go/internal/ast/ast.go:10882 +0x9b
github.com/microsoft/typescript-go/internal/ast.(*Node).ForEachChild(0x9f2c80?, 0xc00473b500?)
	/home/runner/work/tsgolint/tsgolint/typescript-go/internal/ast/ast.go:243 +0x1c
github.com/typescript-eslint/tsgolint/internal/linter.RunLinterOnProgram.func2()
	/home/runner/work/tsgolint/tsgolint/internal/linter/linter.go:373 +0x11e
github.com/microsoft/typescript-go/internal/core.(*parallelWorkGroup).Queue.func1()
	/home/runner/work/tsgolint/tsgolint/typescript-go/internal/core/workgroup.go:40 +0x13
sync.(*WaitGroup).Go.func1()
	/opt/hostedtoolcache/go/1.25.0/x64/src/sync/waitgroup.go:239 +0x4a
created by sync.(*WaitGroup).Go in goroutine 1
	/opt/hostedtoolcache/go/1.25.0/x64/src/sync/waitgroup.go:237 +0x73

Environment

  • Linter: oxlint (invoking tsgolint)
  • Rule: no_unnecessary_type_assertion
  • Platform: Linux

Possible Cause

The fixer logic likely miscalculates the text range to replace when dealing with a JSDoc comment attached to a ParenthesizedExpression. The slice bounds [76:62] (where end < start) suggests an invalid range calculation, possibly assuming a structure similar to TypeAssertionExpression or AsExpression where the operator/type tokens are positioned differently relative to the expression.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions