Skip to content

Commit 97756ce

Browse files
CopilotDanielRosenwasserjakebaileyCopilot
authored
Fix nil pointer dereference in range formatting (#1993)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: DanielRosenwasser <972891+DanielRosenwasser@users.noreply.github.com> Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com> Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent b794761 commit 97756ce

File tree

2 files changed

+68
-2
lines changed

2 files changed

+68
-2
lines changed

internal/format/indent.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,11 @@ func getIndentationForNodeWorker(
6666
// }, { itself contributes nothing.
6767
// prop: 1 L3 - The indentation of the second object literal is best understood by
6868
// }) looking at the relationship between the list and *first* list item.
69-
listLine, _ := getStartLineAndCharacterForNode(firstListChild, sourceFile)
70-
listIndentsChild := firstListChild != nil && listLine > containingListOrParentStartLine
69+
var listIndentsChild bool
70+
if firstListChild != nil {
71+
listLine, _ := getStartLineAndCharacterForNode(firstListChild, sourceFile)
72+
listIndentsChild = listLine > containingListOrParentStartLine
73+
}
7174
actualIndentation := getActualIndentationForListItem(current, sourceFile, options, listIndentsChild)
7275
if actualIndentation != -1 {
7376
return actualIndentation + indentationDelta

internal/ls/format_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,66 @@ func TestGetFormattingEditsAfterKeystroke_SimpleStatement(t *testing.T) {
7070
// Should return nil or empty edits, not panic
7171
_ = edits
7272
}
73+
74+
// Test for issue: Crash in range formatting when requested on a line that is different from the containing function
75+
// This reproduces the panic when formatting a range inside a function body
76+
func TestGetFormattingEditsForRange_FunctionBody(t *testing.T) {
77+
t.Parallel()
78+
79+
testCases := []struct {
80+
name string
81+
text string
82+
startPos int
83+
endPos int
84+
}{
85+
{
86+
name: "return statement in function",
87+
text: "function foo() {\n return (1 + 2);\n}",
88+
startPos: 21, // Start of "return"
89+
endPos: 38, // End of ");"
90+
},
91+
{
92+
name: "function with newline after keyword",
93+
text: "function\nf() {\n}",
94+
startPos: 9, // After "function\n"
95+
endPos: 13, // Inside or after function
96+
},
97+
{
98+
name: "empty function body",
99+
text: "function f() {\n \n}",
100+
startPos: 15, // Inside body
101+
endPos: 17, // Inside body
102+
},
103+
{
104+
name: "after function closing brace",
105+
text: "function f() {\n}",
106+
startPos: 15, // After closing brace
107+
endPos: 15,
108+
},
109+
}
110+
111+
for _, tc := range testCases {
112+
t.Run(tc.name, func(t *testing.T) {
113+
t.Parallel()
114+
sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{
115+
FileName: "/test.ts",
116+
Path: "/test.ts",
117+
}, tc.text, core.ScriptKindTS)
118+
119+
langService := &LanguageService{}
120+
ctx := context.Background()
121+
options := format.GetDefaultFormatCodeSettings("\n")
122+
123+
// This should not panic
124+
edits := langService.getFormattingEditsForRange(
125+
ctx,
126+
sourceFile,
127+
options,
128+
core.NewTextRange(tc.startPos, tc.endPos),
129+
)
130+
131+
// Should not panic
132+
_ = edits // Just ensuring no panic
133+
})
134+
}
135+
}

0 commit comments

Comments
 (0)