Unexpected panic: illegal file offset
I have come across what looks like an issue with the signature help request.
If it matters this test was done on Windows.
This is the test file that I have on disk:
package main
import (
"fmt"
)
func main() {
fmt.Printf("Test")
}
Now consider that file being edited in memory (i.e. unsaved changes) as follows:
...
func main() {
fmt.Printf("Test")
fmt.Printf(
}
When the brace character is entered the client sends the server these two messages:
Sent: Content-Length: 278
{
"jsonrpc":"2.0","method":"textDocument/didChange","params":{
"textDocument":{
"uri":"file:///D:/Go/src/github.com/jussij/Test/test.go","version":2},
"contentChanges":[{"text":"package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc main() {\n\tfmt.Printf(\"Test\")\n\tfmt.Printf(\n}\n"}]
}
}
Sent: Content-Length: 184
{"jsonrpc":"2.0","id":6,"method":"textDocument/signatureHelp","params":{
"textDocument":{
"uri":"file:///D:/Go/src/github.com/jussij/Test/test.go"},"position":{
"line":8,"character":12}}}
The server responds with this error reply:
Reply: {
"id":6,"error":{
"code":0,
"message":"unexpected panic: illegal file offset","data":null},"jsonrpc":"2.0"
}
But if instead I do this in memory edit:
...
func main() {
fmt.Printf(
fmt.Printf("Test")
}
Now the server replies with the expected successful result:
Reply: {"id":7,"result":{
"signatures":[
{"label":"func(format string, a ...interface{}) (n int, err error)",
"documentation":"Printf formats according to a format specifier and .....
{"label":"a []interface{}"}]}],
"activeSignature":0,
"activeParameter":0
},"jsonrpc":"2.0"}
The panic is being fired from this Go code:
// Pos returns the Pos value for the given file offset;
// the offset must be <= f.Size().
// f.Pos(f.Offset(p)) == p.
//
func (f *File) Pos(offset int) Pos {
if offset > f.size {
panic("illegal file offset")
}
return Pos(f.base + offset)
}
Found in this Go file:
/go/src/go/token/position.go
It looks like the server is running checks position against the file on disk and not from the details sent via the did change message.
The offset being sent through is passed the end of file on disk, but that is only because the changes are in memory and have not been saved to disk.
Now if instead if I have these in memory edits and do a completion request instead:
...
func main() {
fmt.Printf("Test")
fmt.
}
That request fires of a similar didChange message but this time the server responded with the completion message reply:
Sent: Content-Length: 231
{"jsonrpc":"2.0","id":8,"method":"textDocument/completion","params":{
"textDocument":{
"uri":"file:///D:/Go/src/github.com/jussij/Test/test.go"},"position":{
"line":8,"character":5},"context":{
"triggerKind":2,"triggerCharacter":"."}
}
}
So for the completion case the server is handling this case correctly but for the signature case it generates a panic.