1
0
mirror of https://github.com/golang/go synced 2024-09-30 20:18:33 -06:00

internal/lsp: fix for limitations of export data

It is impossible to reconstruct a line and column correctly from export data, so
we have to attempt to find open and process the file in order to guess what the
original pos was when we have one that originated in export data.
This occurs in any time in go to definition when the target is not in the same
pacakge as the source.

Change-Id: Ib2ee404d4f1c39d8bd7f1fbc2096d8d6cbeed6f8
Reviewed-on: https://go-review.googlesource.com/c/150044
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
Ian Cottrell 2018-11-17 19:01:23 -05:00
parent d1f8dbfb0b
commit 1aef897494
2 changed files with 33 additions and 7 deletions

View File

@ -17,9 +17,9 @@ import (
)
func (p Position) Format(f fmt.State, c rune) {
fmt.Fprintf(f, "%d", int(p.Line))
fmt.Fprintf(f, "%d", int(p.Line)+1)
if p.Character >= 0 {
fmt.Fprintf(f, ":%d", int(p.Character))
fmt.Fprintf(f, ":%d", int(p.Character)+1)
}
}
@ -28,7 +28,7 @@ func (r Range) Format(f fmt.State, c rune) {
case r.Start == r.End || r.End.Line < 0:
fmt.Fprintf(f, "%v", r.Start)
case r.End.Line == r.Start.Line:
fmt.Fprintf(f, "%v¦%d", r.Start, int(r.End.Character))
fmt.Fprintf(f, "%v¦%d", r.Start, int(r.End.Character)+1)
default:
fmt.Fprintf(f, "%v¦%v", r.Start, r.End)
}

View File

@ -5,11 +5,13 @@
package source
import (
"bytes"
"context"
"fmt"
"go/ast"
"go/token"
"go/types"
"io/ioutil"
"golang.org/x/tools/go/ast/astutil"
)
@ -43,10 +45,7 @@ func Definition(ctx context.Context, f *File, pos token.Pos) (Range, error) {
}
}
}
return Range{
Start: obj.Pos(),
End: obj.Pos() + token.Pos(len([]byte(obj.Name()))), // TODO: use real range of obj
}, nil
return objToRange(f.view.Config.Fset, obj), nil
}
// ident returns the ident plus any extra information needed
@ -93,3 +92,30 @@ func checkIdentifier(f *ast.File, pos token.Pos) (ident, error) {
}
return result, nil
}
func objToRange(fSet *token.FileSet, obj types.Object) Range {
p := obj.Pos()
f := fSet.File(p)
pos := f.Position(p)
if pos.Column == 1 {
// Column is 1, so we probably do not have full position information
// Currently exportdata does not store the column.
// For now we attempt to read the original source and find the identifier
// within the line. If we find it we patch the column to match its offset.
// TODO: we have probably already added the full data for the file to the
// fileset, we ought to track it rather than adding it over and over again
// TODO: if we parse from source, we will never need this hack
if src, err := ioutil.ReadFile(pos.Filename); err == nil {
newF := fSet.AddFile(pos.Filename, -1, len(src))
newF.SetLinesForContent(src)
lineStart := lineStart(newF, pos.Line)
offset := newF.Offset(lineStart)
col := bytes.Index(src[offset:], []byte(obj.Name()))
p = newF.Pos(offset + col)
}
}
return Range{
Start: p,
End: p + token.Pos(len([]byte(obj.Name()))), // TODO: use real range of obj
}
}