Skip to content

Fixed a formatting crash on comments inside blocks starting on first line#2793

Open
Andarist wants to merge 1 commit intomicrosoft:mainfrom
Andarist:fix/format-crash-comment-in-block-first-line
Open

Fixed a formatting crash on comments inside blocks starting on first line#2793
Andarist wants to merge 1 commit intomicrosoft:mainfrom
Andarist:fix/format-crash-comment-in-block-first-line

Conversation

@Andarist
Copy link
Contributor

fixes #2649

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a panic in the LSP formatter that occurred when formatting JavaScript/TypeScript files containing comments inside blocks that start on the first line (e.g., arrow function bodies). The panic was caused by passing a negative indentation value (-1) to strings.Repeat().

Changes:

  • Added a check to prevent passing -1 indentation values to indentTriviaItems
  • Added regression tests for both multiline JSDoc comments and single-line comments in the problematic scenario

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
internal/format/span.go Added guard to check if commentIndentation is -1 before calling indentTriviaItems, preventing the panic
internal/format/comment_test.go Added two regression tests verifying that formatting doesn't panic for comments inside blocks starting on first line

Comment on lines 1059 to +1066
indentNextTokenOrTrivia := true
if len(currentTokenInfo.leadingTrivia) > 0 {
commentIndentation := dynamicIndenation.getIndentationForComment(currentTokenInfo.token.Kind, tokenIndentation, container)
indentNextTokenOrTrivia = w.indentTriviaItems(currentTokenInfo.leadingTrivia, commentIndentation, indentNextTokenOrTrivia, func(item TextRangeWithKind) {
w.insertIndentation(item.Loc.Pos(), commentIndentation, false)
})
if commentIndentation != -1 {
indentNextTokenOrTrivia = w.indentTriviaItems(currentTokenInfo.leadingTrivia, commentIndentation, indentNextTokenOrTrivia, func(item TextRangeWithKind) {
w.insertIndentation(item.Loc.Pos(), commentIndentation, false)
})
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But why? The original code said:

                let indentNextTokenOrTrivia = true;
                if (currentTokenInfo.leadingTrivia) {
                    const commentIndentation = dynamicIndentation.getIndentationForComment(currentTokenInfo.token.kind, tokenIndentation, container);
                    indentNextTokenOrTrivia = indentTriviaItems(currentTokenInfo.leadingTrivia, commentIndentation, indentNextTokenOrTrivia, item => insertIndentation(item.pos, commentIndentation, /*lineAdded*/ false));
                }

which to me means the bug is elsewhere

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

internal/format/comment_test.go:233

  • This subtest only checks len(formatted) > 0, which will always be true since originalText is non-empty—even if the formatter returns no edits or later regresses indentation. Per the project’s bugfix testing guidance, please assert something that demonstrates the fix (e.g., that the JSDoc text is preserved and that the comment line is not moved to column 0 / remains indented).
		edits := format.FormatDocument(ctx, sourceFile)
		formatted := applyBulkEdits(originalText, edits)
		assert.Check(t, len(formatted) > 0, "formatted text should not be empty")
	})

Comment on lines +259 to +262
edits := format.FormatDocument(ctx, sourceFile)
formatted := applyBulkEdits(originalText, edits)
assert.Check(t, len(formatted) > 0, "formatted text should not be empty")
})
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This subtest also uses only len(formatted) > 0, which is effectively a no-op because originalText is non-empty. Please add an assertion that demonstrates the intended behavior (e.g., the single-line comment remains indented and is not reformatted to column 0), so the test will catch regressions beyond “did not panic”.

This issue also appears on line 230 of the same file.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines 1061 to +1066
commentIndentation := dynamicIndenation.getIndentationForComment(currentTokenInfo.token.Kind, tokenIndentation, container)
indentNextTokenOrTrivia = w.indentTriviaItems(currentTokenInfo.leadingTrivia, commentIndentation, indentNextTokenOrTrivia, func(item TextRangeWithKind) {
w.insertIndentation(item.Loc.Pos(), commentIndentation, false)
})
if commentIndentation != -1 {
indentNextTokenOrTrivia = w.indentTriviaItems(currentTokenInfo.leadingTrivia, commentIndentation, indentNextTokenOrTrivia, func(item TextRangeWithKind) {
w.insertIndentation(item.Loc.Pos(), commentIndentation, false)
})
}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new guard avoids passing the sentinel indentation (-1) into indent/insertIndentation (and thus avoids the strings.Repeat panic), but it also means leading comments won’t be indented at all in this scenario. The underlying source of commentIndentation == -1 appears to be that computeIndentation can return w.indentationOnLastIndentedLine (initialized to -1) when startLine == w.lastIndentedLine (which is never initialized and defaults to 0), which is exactly the “block opens on first line” case. Consider initializing w.lastIndentedLine to -1 alongside indentationOnLastIndentedLine (or otherwise ensuring indentation is never computed as -1 for in-range tokens), so comment indentation can be computed rather than skipped.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LSP Panic: strings: negative Repeat count when formatting JSDoc within nested scope

3 participants

Comments