1
0
mirror of https://github.com/golang/go synced 2024-11-18 14:14:46 -07:00

internal/lsp: fix definition tests to use golden files

specifically it uses them for the guru compatability tests
This change radically increases the test coverage of the godef tests as it now
works for all the jump to definition tests not just the specialized ones.

Change-Id: I63547138566ac3de56344dcfddb758ed5f362a06
Reviewed-on: https://go-review.googlesource.com/c/tools/+/174937
Run-TryBot: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
Ian Cottrell 2019-04-29 14:57:27 -04:00
parent 45e43b2cb4
commit 4ca280b5bd
14 changed files with 866 additions and 198 deletions

View File

@ -8,10 +8,10 @@ import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"testing"
"unicode"
"unicode/utf8"
"golang.org/x/tools/go/packages/packagestest"
"golang.org/x/tools/internal/lsp/cmd"
@ -21,8 +21,9 @@ import (
var isRace = false
type runner struct {
data *tests.Data
app *cmd.Application
exporter packagestest.Exporter
data *tests.Data
app *cmd.Application
}
func TestCommandLine(t *testing.T) {
@ -34,7 +35,8 @@ func testCommandLine(t *testing.T, exporter packagestest.Exporter) {
defer data.Exported.Cleanup()
r := &runner{
data: data,
exporter: exporter,
data: data,
app: &cmd.Application{
Config: *data.Exported.Config,
},
@ -84,20 +86,34 @@ func captureStdOut(t testing.TB, f func()) string {
// normalizePaths replaces all paths present in s with just the fragment portion
// this is used to make golden files not depend on the temporary paths of the files
func (r *runner) normalizePaths(s string) string {
func normalizePaths(data *tests.Data, s string) string {
type entry struct {
path string
index int
path string
index int
fragment string
}
match := make([]entry, len(r.data.Exported.Modules))
match := make([]entry, 0, len(data.Exported.Modules))
// collect the initial state of all the matchers
for i, m := range r.data.Exported.Modules {
// any random file will do, we collect the first one only
for f := range m.Files {
path := strings.TrimSuffix(r.data.Exported.File(m.Name, f), f)
index := strings.Index(s, path)
match[i] = entry{path, index}
break
for _, m := range data.Exported.Modules {
for fragment := range m.Files {
filename := data.Exported.File(m.Name, fragment)
index := strings.Index(s, filename)
if index >= 0 {
match = append(match, entry{filename, index, fragment})
}
if slash := filepath.ToSlash(filename); slash != filename {
index := strings.Index(s, slash)
if index >= 0 {
match = append(match, entry{slash, index, fragment})
}
}
quoted := strconv.Quote(filename)
if escaped := quoted[1 : len(quoted)-1]; escaped != filename {
index := strings.Index(s, escaped)
if index >= 0 {
match = append(match, entry{escaped, index, fragment})
}
}
}
}
// result should be the same or shorter than the input
@ -122,20 +138,10 @@ func (r *runner) normalizePaths(s string) string {
n := &match[next]
// copy up to the start of the match
buf.WriteString(s[last:n.index])
// skip over the non fragment prefix
// skip over the filename
last = n.index + len(n.path)
// now try to convert the fragment part
for last < len(s) {
r, size := utf8.DecodeRuneInString(s[last:])
if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '/' {
buf.WriteRune(r)
} else if r == '\\' {
buf.WriteRune('/')
} else {
break
}
last += size
}
// add in the fragment instead
buf.WriteString(n.fragment)
// see what the next match for this path is
n.index = strings.Index(s[last:], n.path)
if n.index >= 0 {

View File

@ -6,14 +6,12 @@ package cmd_test
import (
"context"
"flag"
"fmt"
"os"
"os/exec"
"path/filepath"
"regexp"
"runtime"
"strconv"
"strings"
"testing"
@ -28,7 +26,20 @@ const (
expectedTypeDefinitionsCount = 2
)
var verifyGuru = flag.Bool("verify-guru", false, "Check that the guru compatability matches")
type godefMode int
const (
plainGodef = godefMode(1 << iota)
jsonGoDef
guruGoDef
)
var godefModes = []godefMode{
plainGodef,
jsonGoDef,
guruGoDef,
jsonGoDef | guruGoDef,
}
func TestDefinitionHelpExample(t *testing.T) {
if runtime.GOOS == "android" {
@ -55,132 +66,96 @@ func TestDefinitionHelpExample(t *testing.T) {
}
}
var brokenDefinitionTests = map[string]bool{
// The following tests all have extra information in the description
"A-definition-json-guru": true,
"err-definition-json-guru": true,
"myUnclosedIf-definition-json-guru": true,
"Other-definition-json-guru": true,
"RandomParamY-definition-json-guru": true,
"S1-definition-json-guru": true,
"S2-definition-json-guru": true,
"Stuff-definition-json-guru": true,
"Thing-definition-json-guru": true,
"Things-definition-json-guru": true,
}
func (r *runner) Definition(t *testing.T, data tests.Definitions) {
for _, d := range data {
if d.IsType {
// TODO: support type definition queries
continue
}
args := []string{"-remote=internal", "query"}
if d.Flags != "" {
args = append(args, strings.Split(d.Flags, " ")...)
}
args = append(args, "definition")
src := span.New(d.Src.URI(), span.NewPoint(0, 0, d.Src.Start().Offset()), span.Point{})
args = append(args, fmt.Sprint(src))
got := captureStdOut(t, func() {
tool.Main(context.Background(), r.app, args)
})
pattern := newPattern(d.Match, d.Def)
if !pattern.matches(got) {
t.Errorf("definition %v\nexpected:\n%s\ngot:\n%s", args, pattern, got)
}
if *verifyGuru {
moduleMode := r.data.Exported.File(r.data.Exported.Modules[0].Name, "go.mod") != ""
var guruArgs []string
runGuru := false
if !moduleMode {
for _, arg := range args {
switch {
case arg == "query":
// just ignore this one
case arg == "-json":
guruArgs = append(guruArgs, arg)
case arg == "-emulate=guru":
// if we don't see this one we should not run guru
runGuru = true
case strings.HasPrefix(arg, "-"):
// unknown flag, ignore it
break
default:
guruArgs = append(guruArgs, arg)
}
}
d.Src = span.New(d.Src.URI(), span.NewPoint(0, 0, d.Src.Start().Offset()), span.Point{})
for _, mode := range godefModes {
args := []string{"-remote=internal", "query"}
tag := d.Name + "-definition"
if mode&jsonGoDef != 0 {
tag += "-json"
args = append(args, "-json")
}
if runGuru {
if mode&guruGoDef != 0 {
if r.exporter.Name() != "GOPATH" {
//only run guru compatability tests in GOPATH mode
continue
}
if d.Name == "PackageFoo" {
//guru does not support definition on packages
continue
}
tag += "-guru"
args = append(args, "-emulate=guru")
}
if _, found := brokenDefinitionTests[tag]; found {
continue
}
args = append(args, "definition")
uri := d.Src.URI()
filename, err := uri.Filename()
if err != nil {
t.Fatal(err)
}
args = append(args, fmt.Sprint(d.Src))
got := captureStdOut(t, func() {
tool.Main(context.Background(), r.app, args)
})
got = normalizePaths(r.data, got)
if mode&jsonGoDef != 0 && runtime.GOOS == "windows" {
got = strings.Replace(got, "file:///", "file://", -1)
}
if mode&guruGoDef == 0 {
expect := string(r.data.Golden(tag, filename, func() ([]byte, error) {
return []byte(got), nil
}))
if got != expect {
t.Errorf("definition %v failed with %#v expected:\n%s\ngot:\n%s", tag, args, expect, got)
}
continue
}
guruArgs := []string{}
if mode&jsonGoDef != 0 {
guruArgs = append(guruArgs, "-json")
}
guruArgs = append(guruArgs, "definition", fmt.Sprint(d.Src))
expect := strings.TrimSpace(string(r.data.Golden(tag, filename, func() ([]byte, error) {
cmd := exec.Command("guru", guruArgs...)
cmd.Env = r.data.Exported.Config.Env
out, err := cmd.CombinedOutput()
out, _ := cmd.Output()
if err != nil {
t.Errorf("Could not run guru %v: %v\n%s", guruArgs, err, out)
} else {
guru := strings.TrimSpace(string(out))
if !pattern.matches(guru) {
t.Errorf("definition %v\nexpected:\n%s\nguru gave:\n%s", args, pattern, guru)
if _, ok := err.(*exec.ExitError); !ok {
return nil, fmt.Errorf("Could not run guru %v: %v\n%s", guruArgs, err, out)
}
}
result := normalizePaths(r.data, string(out))
// guru sometimes puts the full package path in type names, but we don't
if mode&jsonGoDef == 0 && d.Name != "AImport" {
result = strings.Replace(result, "golang.org/x/tools/internal/lsp/godef/", "", -1)
}
return []byte(result), nil
})))
if expect != "" && !strings.HasPrefix(got, expect) {
t.Errorf("definition %v failed with %#v expected:\n%q\ngot:\n%q", tag, args, expect, got)
}
}
}
}
type pattern struct {
raw string
expanded []string
matchAll bool
}
func newPattern(s string, def span.Span) pattern {
p := pattern{raw: s}
if s == "" {
p.expanded = []string{fmt.Sprintf("%v: ", def)}
return p
}
p.matchAll = strings.HasSuffix(s, "$$")
for _, fragment := range strings.Split(s, "$$") {
p.expanded = append(p.expanded, os.Expand(fragment, func(name string) string {
switch name {
case "file":
fname, _ := def.URI().Filename()
return fname
case "efile":
fname, _ := def.URI().Filename()
qfile := strconv.Quote(fname)
return qfile[1 : len(qfile)-1]
case "euri":
quri := strconv.Quote(string(def.URI()))
return quri[1 : len(quri)-1]
case "line":
return fmt.Sprint(def.Start().Line())
case "col":
return fmt.Sprint(def.Start().Column())
case "offset":
return fmt.Sprint(def.Start().Offset())
case "eline":
return fmt.Sprint(def.End().Line())
case "ecol":
return fmt.Sprint(def.End().Column())
case "eoffset":
return fmt.Sprint(def.End().Offset())
default:
return name
}
}))
}
return p
}
func (p pattern) String() string {
return strings.Join(p.expanded, "$$")
}
func (p pattern) matches(s string) bool {
if len(p.expanded) == 0 {
return false
}
if !strings.HasPrefix(s, p.expanded[0]) {
return false
}
remains := s[len(p.expanded[0]):]
for _, fragment := range p.expanded[1:] {
i := strings.Index(remains, fragment)
if i < 0 {
return false
}
remains = remains[i+len(fragment):]
}
if !p.matchAll {
return true
}
return len(remains) == 0
}

View File

@ -34,7 +34,7 @@ func (r *runner) Format(t *testing.T, data tests.Formats) {
expect := string(r.data.Golden(tag, filename, func() ([]byte, error) {
cmd := exec.Command("gofmt", args...)
contents, _ := cmd.Output() // ignore error, sometimes we have intentionally ungofmt-able files
contents = []byte(r.normalizePaths(fixFileHeader(string(contents))))
contents = []byte(normalizePaths(r.data, fixFileHeader(string(contents))))
return contents, nil
}))
if expect == "" {
@ -46,7 +46,7 @@ func (r *runner) Format(t *testing.T, data tests.Formats) {
got := captureStdOut(t, func() {
tool.Main(context.Background(), app, append([]string{"-remote=internal", "format"}, args...))
})
got = r.normalizePaths(got)
got = normalizePaths(r.data, got)
// check the first two lines are the expected file header
if expect != got {
t.Errorf("format failed with %#v expected:\n%s\ngot:\n%s", args, expect, got)

View File

@ -1,4 +1,4 @@
#!/bin/bash
find ./internal/lsp/ -name *.golden -delete
go test ./internal/lsp/ ./internal/lsp/cmd -golden
go test ./internal/lsp/ ./internal/lsp/cmd ./internal/lsp/source -golden

View File

@ -1,6 +1,82 @@
-- Random-definition --
godef/a/random.go:3:6-12: defined here as func Random() int
-- Random-definition-guru --
-- Random-definition-json --
{
"span": {
"uri": "file://godef/a/random.go",
"start": {
"line": 3,
"column": 6,
"offset": 16
},
"end": {
"line": 3,
"column": 12,
"offset": 22
}
},
"description": "func Random() int"
}
-- Random-definition-json-guru --
-- Random-hover --
func Random() int
-- Random2-definition --
godef/a/random.go:8:6-13: defined here as func Random2(y int) int
-- Random2-definition-guru --
godef/a/random.go:8:6: defined here as func Random2(y int) int
-- Random2-definition-json --
{
"span": {
"uri": "file://godef/a/random.go",
"start": {
"line": 8,
"column": 6,
"offset": 71
},
"end": {
"line": 8,
"column": 13,
"offset": 78
}
},
"description": "func Random2(y int) int"
}
-- Random2-definition-json-guru --
{
"objpos": "godef/a/random.go:8:6",
"desc": "func Random2(y int) int"
}
-- Random2-hover --
func Random2(y int) int
-- err-definition --
godef/a/a.go:14:6-9: defined here as var err error
-- err-definition-guru --
godef/a/a.go:14:6: defined here as var err
-- err-definition-json --
{
"span": {
"uri": "file://godef/a/a.go",
"start": {
"line": 14,
"column": 6,
"offset": 201
},
"end": {
"line": 14,
"column": 9,
"offset": 204
}
},
"description": "var err error"
}
-- err-hover --
var err error

View File

@ -25,46 +25,15 @@ func useThings() {
}
/*@
definition(aStructType, "", Thing, "$file:$line:$col-$ecol: defined here as type Thing struct{Member string}")
definition(aStructType, "-emulate=guru", Thing, "$file:$line:$col: defined here as type Thing")
definition(aMember, "", Member, "$file:$line:$col-$ecol: defined here as field Member string")
definition(aMember, "-emulate=guru", Member, "$file:$line:$col: defined here as field Member string")
definition(aVar, "", Other, "$file:$line:$col-$ecol: defined here as var Other Thing")
definition(aVar, "-emulate=guru", Other, "$file:$line:$col: defined here as var Other")
definition(aFunc, "", Things, "$file:$line:$col-$ecol: defined here as func Things(val []string) []Thing")
definition(aFunc, "-emulate=guru", Things, "$file:$line:$col: defined here as func Things")
definition(aMethod, "", Method, "$file:$line:$col-$ecol: defined here as func (Thing).Method(i int) string")
definition(aMethod, "-emulate=guru", Method, "$file:$line:$col: defined here as func (Thing).Method(i int) string")
godef(aStructType, Thing)
godef(aMember, Member)
godef(aVar, Other)
godef(aFunc, Things)
godef(aMethod, Method)
//param
//package name
//const
//anon field
// JSON tests
definition(aStructType, "-json", Thing, `{
"span": {
"uri": "$euri",
"start": {
"line": $line,
"column": $col,
"offset": $offset
},
"end": {
"line": $eline,
"column": $ecol,
"offset": $eoffset
}
},
"description": "type Thing struct{Member string}"
}`)
definition(aStructType, "-json -emulate=guru", Thing, `{
"objpos": "$efile:$line:$col",
"desc": "type Thing$$"
}`)
*/

View File

@ -0,0 +1,137 @@
-- Member-definition --
godef/a/d.go:6:2-8: defined here as field Member string
-- Member-definition-guru --
godef/a/d.go:6:2: defined here as field Member string
-- Member-definition-json --
{
"span": {
"uri": "file://godef/a/d.go",
"start": {
"line": 6,
"column": 2,
"offset": 55
},
"end": {
"line": 6,
"column": 8,
"offset": 61
}
},
"description": "field Member string"
}
-- Member-definition-json-guru --
{
"objpos": "godef/a/d.go:6:2",
"desc": "field Member string"
}
-- Member-hover --
field Member string
-- Method-definition --
godef/a/d.go:15:16-22: defined here as func (Thing).Method(i int) string
-- Method-definition-guru --
godef/a/d.go:15:16: defined here as func (Thing).Method(i int) string
-- Method-definition-json --
{
"span": {
"uri": "file://godef/a/d.go",
"start": {
"line": 15,
"column": 16,
"offset": 184
},
"end": {
"line": 15,
"column": 22,
"offset": 190
}
},
"description": "func (Thing).Method(i int) string"
}
-- Method-definition-json-guru --
{
"objpos": "godef/a/d.go:15:16",
"desc": "func (Thing).Method(i int) string"
}
-- Method-hover --
func (Thing).Method(i int) string
-- Other-definition --
godef/a/d.go:9:5-10: defined here as var Other Thing
-- Other-definition-guru --
godef/a/d.go:9:5: defined here as var Other
-- Other-definition-json --
{
"span": {
"uri": "file://godef/a/d.go",
"start": {
"line": 9,
"column": 5,
"offset": 86
},
"end": {
"line": 9,
"column": 10,
"offset": 91
}
},
"description": "var Other Thing"
}
-- Other-hover --
var Other Thing
-- Thing-definition --
godef/a/d.go:5:6-11: defined here as type Thing struct{Member string}
-- Thing-definition-guru --
godef/a/d.go:5:6: defined here as type Thing
-- Thing-definition-json --
{
"span": {
"uri": "file://godef/a/d.go",
"start": {
"line": 5,
"column": 6,
"offset": 30
},
"end": {
"line": 5,
"column": 11,
"offset": 35
}
},
"description": "type Thing struct{Member string}"
}
-- Thing-hover --
type Thing struct{Member string}
-- Things-definition --
godef/a/d.go:11:6-12: defined here as func Things(val []string) []Thing
-- Things-definition-guru --
godef/a/d.go:11:6: defined here as func Things
-- Things-definition-json --
{
"span": {
"uri": "file://godef/a/d.go",
"start": {
"line": 11,
"column": 6,
"offset": 113
},
"end": {
"line": 11,
"column": 12,
"offset": 119
}
},
"description": "func Things(val []string) []Thing"
}
-- Things-hover --
func Things(val []string) []Thing

View File

@ -1,6 +1,82 @@
-- PosSum-definition --
godef/a/random.go:16:15-18: defined here as func (*Pos).Sum() int
-- PosSum-definition-guru --
-- PosSum-definition-json --
{
"span": {
"uri": "file://godef/a/random.go",
"start": {
"line": 16,
"column": 15,
"offset": 248
},
"end": {
"line": 16,
"column": 18,
"offset": 251
}
},
"description": "func (*Pos).Sum() int"
}
-- PosSum-definition-json-guru --
-- PosSum-hover --
func (*Pos).Sum() int
-- PosX-definition --
godef/a/random.go:13:2-3: defined here as field x int
-- PosX-definition-guru --
godef/a/random.go:13:2: defined here as field x int
-- PosX-definition-json --
{
"span": {
"uri": "file://godef/a/random.go",
"start": {
"line": 13,
"column": 2,
"offset": 187
},
"end": {
"line": 13,
"column": 3,
"offset": 188
}
},
"description": "field x int"
}
-- PosX-definition-json-guru --
{
"objpos": "godef/a/random.go:13:2",
"desc": "field x int"
}
-- PosX-hover --
field x int
-- RandomParamY-definition --
godef/a/random.go:8:14-15: defined here as var y int
-- RandomParamY-definition-guru --
godef/a/random.go:8:14: defined here as var y
-- RandomParamY-definition-json --
{
"span": {
"uri": "file://godef/a/random.go",
"start": {
"line": 8,
"column": 14,
"offset": 79
},
"end": {
"line": 8,
"column": 15,
"offset": 80
}
},
"description": "var y int"
}
-- RandomParamY-hover --
var y int

View File

@ -1,20 +1,277 @@
-- A-definition --
godef/a/a.go:7:6-7: defined here as type a.A string
-- A-definition-guru --
godef/a/a.go:7:6: defined here as type a.A
-- A-definition-json --
{
"span": {
"uri": "file://godef/a/a.go",
"start": {
"line": 7,
"column": 6,
"offset": 75
},
"end": {
"line": 7,
"column": 7,
"offset": 76
}
},
"description": "type a.A string"
}
-- A-hover --
type a.A string
-- AImport-definition --
godef/b/b.go:5:2-3: defined here as package a ("golang.org/x/tools/internal/lsp/godef/a")
-- AImport-definition-guru --
godef/b/b.go:5:2: defined here as package a ("golang.org/x/tools/internal/lsp/godef/a")
-- AImport-definition-json --
{
"span": {
"uri": "file://godef/b/b.go",
"start": {
"line": 5,
"column": 2,
"offset": 121
},
"end": {
"line": 5,
"column": 3,
"offset": 122
}
},
"description": "package a (\"golang.org/x/tools/internal/lsp/godef/a\")"
}
-- AImport-definition-json-guru --
{
"objpos": "godef/b/b.go:5:2",
"desc": "package a (\"golang.org/x/tools/internal/lsp/godef/a\")"
}
-- AImport-hover --
package a ("golang.org/x/tools/internal/lsp/godef/a")
-- PackageFoo-definition --
foo/foo.go:1:9-12: defined here as
-- PackageFoo-definition-json --
{
"span": {
"uri": "file://foo/foo.go",
"start": {
"line": 1,
"column": 9,
"offset": 8
},
"end": {
"line": 1,
"column": 12,
"offset": 11
}
},
"description": ""
}
-- PackageFoo-hover --
-- S1-definition --
godef/b/b.go:8:6-8: defined here as type S1 struct{F1 int; S2; a.A}
-- S1-definition-guru --
godef/b/b.go:8:6: defined here as type S1
-- S1-definition-json --
{
"span": {
"uri": "file://godef/b/b.go",
"start": {
"line": 8,
"column": 6,
"offset": 196
},
"end": {
"line": 8,
"column": 8,
"offset": 198
}
},
"description": "type S1 struct{F1 int; S2; a.A}"
}
-- S1-hover --
type S1 struct{F1 int; S2; a.A}
-- S1F1-definition --
godef/b/b.go:9:2-4: defined here as field F1 int
-- S1F1-definition-guru --
godef/b/b.go:9:2: defined here as field F1 int
-- S1F1-definition-json --
{
"span": {
"uri": "file://godef/b/b.go",
"start": {
"line": 9,
"column": 2,
"offset": 215
},
"end": {
"line": 9,
"column": 4,
"offset": 217
}
},
"description": "field F1 int"
}
-- S1F1-definition-json-guru --
{
"objpos": "godef/b/b.go:9:2",
"desc": "field F1 int"
}
-- S1F1-hover --
field F1 int
-- S1S2-definition --
godef/b/b.go:10:2-4: defined here as field S2 S2
-- S1S2-definition-guru --
godef/b/b.go:10:2: defined here as field S2 S2
-- S1S2-definition-json --
{
"span": {
"uri": "file://godef/b/b.go",
"start": {
"line": 10,
"column": 2,
"offset": 244
},
"end": {
"line": 10,
"column": 4,
"offset": 246
}
},
"description": "field S2 S2"
}
-- S1S2-definition-json-guru --
{
"objpos": "godef/b/b.go:10:2",
"desc": "field S2 S2"
}
-- S1S2-hover --
field S2 S2
-- S2-definition --
godef/b/b.go:14:6-8: defined here as type S2 struct{F1 string; F2 int; *a.A}
-- S2-definition-guru --
godef/b/b.go:14:6: defined here as type S2
-- S2-definition-json --
{
"span": {
"uri": "file://godef/b/b.go",
"start": {
"line": 14,
"column": 6,
"offset": 323
},
"end": {
"line": 14,
"column": 8,
"offset": 325
}
},
"description": "type S2 struct{F1 string; F2 int; *a.A}"
}
-- S2-hover --
type S2 struct{F1 string; F2 int; *a.A}
-- S2F1-definition --
godef/b/b.go:15:2-4: defined here as field F1 string
-- S2F1-definition-guru --
godef/b/b.go:15:2: defined here as field F1 string
-- S2F1-definition-json --
{
"span": {
"uri": "file://godef/b/b.go",
"start": {
"line": 15,
"column": 2,
"offset": 342
},
"end": {
"line": 15,
"column": 4,
"offset": 344
}
},
"description": "field F1 string"
}
-- S2F1-definition-json-guru --
{
"objpos": "godef/b/b.go:15:2",
"desc": "field F1 string"
}
-- S2F1-hover --
field F1 string
-- S2F2-definition --
godef/b/b.go:16:2-4: defined here as field F2 int
-- S2F2-definition-guru --
godef/b/b.go:16:2: defined here as field F2 int
-- S2F2-definition-json --
{
"span": {
"uri": "file://godef/b/b.go",
"start": {
"line": 16,
"column": 2,
"offset": 375
},
"end": {
"line": 16,
"column": 4,
"offset": 377
}
},
"description": "field F2 int"
}
-- S2F2-definition-json-guru --
{
"objpos": "godef/b/b.go:16:2",
"desc": "field F2 int"
}
-- S2F2-hover --
field F2 int
-- Stuff-definition --
godef/a/a.go:9:6-11: defined here as func a.Stuff()
-- Stuff-definition-guru --
godef/a/a.go:9:6: defined here as func a.Stuff
-- Stuff-definition-json --
{
"span": {
"uri": "file://godef/a/a.go",
"start": {
"line": 9,
"column": 6,
"offset": 95
},
"end": {
"line": 9,
"column": 11,
"offset": 100
}
},
"description": "func a.Stuff()"
}
-- Stuff-hover --
func a.Stuff()

View File

@ -1,4 +1,56 @@
-- S1-definition --
godef/b/b.go:8:6-8: defined here as type S1 struct{F1 int; S2; a.A}
-- S1-definition-guru --
godef/b/b.go:8:6: defined here as type S1 struct{F1 int; S2; a.A}
-- S1-definition-json --
{
"span": {
"uri": "file://godef/b/b.go",
"start": {
"line": 8,
"column": 6,
"offset": 196
},
"end": {
"line": 8,
"column": 8,
"offset": 198
}
},
"description": "type S1 struct{F1 int; S2; a.A}"
}
-- S1-hover --
type S1 struct{F1 int; S2; a.A}
-- S1F1-definition --
godef/b/b.go:9:2-4: defined here as field F1 int
-- S1F1-definition-guru --
godef/b/b.go:9:2: defined here as field F1 int
-- S1F1-definition-json --
{
"span": {
"uri": "file://godef/b/b.go",
"start": {
"line": 9,
"column": 2,
"offset": 215
},
"end": {
"line": 9,
"column": 4,
"offset": 217
}
},
"description": "field F1 int"
}
-- S1F1-definition-json-guru --
{
"objpos": "godef/b/b.go:9:2",
"desc": "field F1 int"
}
-- S1F1-hover --
field F1 int

View File

@ -14,15 +14,8 @@ func useThings() {
}
/*@
definition(bStructType, "", Thing, "$file:$line:$col-$ecol: defined here as type a.Thing struct{Member string}")
definition(bStructType, "-emulate=guru", Thing, "$file:$line:$col: defined here as type $$a.Thing")
definition(bMember, "", Member, "$file:$line:$col-$ecol: defined here as field Member string")
definition(bMember, "-emulate=guru", Member, "$file:$line:$col: defined here as field Member string")
definition(bVar, "", Other, "$file:$line:$col-$ecol: defined here as var a.Other a.Thing")
definition(bVar, "-emulate=guru", Other, "$file:$line:$col: defined here as var $$a.Other")
definition(bFunc, "", Things, "$file:$line:$col-$ecol: defined here as func a.Things(val []string) []a.Thing")
definition(bFunc, "-emulate=guru", Things, "$file:$line:$col: defined here as func $$a.Things")
godef(bStructType, Thing)
godef(bMember, Member)
godef(bVar, Other)
godef(bFunc, Things)
*/

View File

@ -0,0 +1,106 @@
-- Member-definition --
godef/a/d.go:6:2-8: defined here as field Member string
-- Member-definition-guru --
godef/a/d.go:6:2: defined here as field Member string
-- Member-definition-json --
{
"span": {
"uri": "file://godef/a/d.go",
"start": {
"line": 6,
"column": 2,
"offset": 55
},
"end": {
"line": 6,
"column": 8,
"offset": 61
}
},
"description": "field Member string"
}
-- Member-definition-json-guru --
{
"objpos": "godef/a/d.go:6:2",
"desc": "field Member string"
}
-- Member-hover --
field Member string
-- Other-definition --
godef/a/d.go:9:5-10: defined here as var a.Other a.Thing
-- Other-definition-guru --
godef/a/d.go:9:5: defined here as var a.Other
-- Other-definition-json --
{
"span": {
"uri": "file://godef/a/d.go",
"start": {
"line": 9,
"column": 5,
"offset": 86
},
"end": {
"line": 9,
"column": 10,
"offset": 91
}
},
"description": "var a.Other a.Thing"
}
-- Other-hover --
var a.Other a.Thing
-- Thing-definition --
godef/a/d.go:5:6-11: defined here as type a.Thing struct{Member string}
-- Thing-definition-guru --
godef/a/d.go:5:6: defined here as type a.Thing
-- Thing-definition-json --
{
"span": {
"uri": "file://godef/a/d.go",
"start": {
"line": 5,
"column": 6,
"offset": 30
},
"end": {
"line": 5,
"column": 11,
"offset": 35
}
},
"description": "type a.Thing struct{Member string}"
}
-- Thing-hover --
type a.Thing struct{Member string}
-- Things-definition --
godef/a/d.go:11:6-12: defined here as func a.Things(val []string) []a.Thing
-- Things-definition-guru --
godef/a/d.go:11:6: defined here as func a.Things
-- Things-definition-json --
{
"span": {
"uri": "file://godef/a/d.go",
"start": {
"line": 11,
"column": 6,
"offset": 113
},
"end": {
"line": 11,
"column": 12,
"offset": 119
}
},
"description": "func a.Things(val []string) []a.Thing"
}
-- Things-hover --
func a.Things(val []string) []a.Thing

View File

@ -1,2 +1,25 @@
-- myUnclosedIf-definition --
godef/broken/unclosedIf.go:7:7-19: defined here as var myUnclosedIf string
-- myUnclosedIf-definition-guru --
godef/broken/unclosedIf.go:7:7: defined here as var myUnclosedIf
-- myUnclosedIf-definition-json --
{
"span": {
"uri": "file://godef/broken/unclosedIf.go",
"start": {
"line": 7,
"column": 7,
"offset": 68
},
"end": {
"line": 7,
"column": 19,
"offset": 80
}
},
"description": "var myUnclosedIf string"
}
-- myUnclosedIf-hover --
var myUnclosedIf string

View File

@ -31,7 +31,7 @@ const (
ExpectedCompletionsCount = 97
ExpectedDiagnosticsCount = 17
ExpectedFormatCount = 5
ExpectedDefinitionsCount = 24
ExpectedDefinitionsCount = 33
ExpectedTypeDefinitionsCount = 2
ExpectedHighlightsCount = 2
ExpectedSymbolsCount = 1
@ -97,9 +97,7 @@ type Definition struct {
Name string
Src span.Span
IsType bool
Flags string
Def span.Span
Match string
}
type CompletionSnippet struct {