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" "bytes"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath"
"strconv"
"strings" "strings"
"testing" "testing"
"unicode"
"unicode/utf8"
"golang.org/x/tools/go/packages/packagestest" "golang.org/x/tools/go/packages/packagestest"
"golang.org/x/tools/internal/lsp/cmd" "golang.org/x/tools/internal/lsp/cmd"
@ -21,6 +21,7 @@ import (
var isRace = false var isRace = false
type runner struct { type runner struct {
exporter packagestest.Exporter
data *tests.Data data *tests.Data
app *cmd.Application app *cmd.Application
} }
@ -34,6 +35,7 @@ func testCommandLine(t *testing.T, exporter packagestest.Exporter) {
defer data.Exported.Cleanup() defer data.Exported.Cleanup()
r := &runner{ r := &runner{
exporter: exporter,
data: data, data: data,
app: &cmd.Application{ app: &cmd.Application{
Config: *data.Exported.Config, 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 // 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 // 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 { type entry struct {
path string path string
index int 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 // collect the initial state of all the matchers
for i, m := range r.data.Exported.Modules { for _, m := range data.Exported.Modules {
// any random file will do, we collect the first one only for fragment := range m.Files {
for f := range m.Files { filename := data.Exported.File(m.Name, fragment)
path := strings.TrimSuffix(r.data.Exported.File(m.Name, f), f) index := strings.Index(s, filename)
index := strings.Index(s, path) if index >= 0 {
match[i] = entry{path, index} match = append(match, entry{filename, index, fragment})
break }
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 // result should be the same or shorter than the input
@ -122,20 +138,10 @@ func (r *runner) normalizePaths(s string) string {
n := &match[next] n := &match[next]
// copy up to the start of the match // copy up to the start of the match
buf.WriteString(s[last:n.index]) buf.WriteString(s[last:n.index])
// skip over the non fragment prefix // skip over the filename
last = n.index + len(n.path) last = n.index + len(n.path)
// now try to convert the fragment part // add in the fragment instead
for last < len(s) { buf.WriteString(n.fragment)
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
}
// see what the next match for this path is // see what the next match for this path is
n.index = strings.Index(s[last:], n.path) n.index = strings.Index(s[last:], n.path)
if n.index >= 0 { if n.index >= 0 {

View File

@ -6,14 +6,12 @@ package cmd_test
import ( import (
"context" "context"
"flag"
"fmt" "fmt"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"regexp" "regexp"
"runtime" "runtime"
"strconv"
"strings" "strings"
"testing" "testing"
@ -28,7 +26,20 @@ const (
expectedTypeDefinitionsCount = 2 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) { func TestDefinitionHelpExample(t *testing.T) {
if runtime.GOOS == "android" { 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) { func (r *runner) Definition(t *testing.T, data tests.Definitions) {
for _, d := range data { for _, d := range data {
if d.IsType { if d.IsType {
// TODO: support type definition queries // TODO: support type definition queries
continue continue
} }
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"} args := []string{"-remote=internal", "query"}
if d.Flags != "" { tag := d.Name + "-definition"
args = append(args, strings.Split(d.Flags, " ")...) if mode&jsonGoDef != 0 {
tag += "-json"
args = append(args, "-json")
}
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") args = append(args, "definition")
src := span.New(d.Src.URI(), span.NewPoint(0, 0, d.Src.Start().Offset()), span.Point{}) uri := d.Src.URI()
args = append(args, fmt.Sprint(src)) filename, err := uri.Filename()
if err != nil {
t.Fatal(err)
}
args = append(args, fmt.Sprint(d.Src))
got := captureStdOut(t, func() { got := captureStdOut(t, func() {
tool.Main(context.Background(), r.app, args) tool.Main(context.Background(), r.app, args)
}) })
pattern := newPattern(d.Match, d.Def) got = normalizePaths(r.data, got)
if !pattern.matches(got) { if mode&jsonGoDef != 0 && runtime.GOOS == "windows" {
t.Errorf("definition %v\nexpected:\n%s\ngot:\n%s", args, pattern, got) got = strings.Replace(got, "file:///", "file://", -1)
} }
if *verifyGuru { if mode&guruGoDef == 0 {
moduleMode := r.data.Exported.File(r.data.Exported.Modules[0].Name, "go.mod") != "" expect := string(r.data.Golden(tag, filename, func() ([]byte, error) {
var guruArgs []string return []byte(got), nil
runGuru := false }))
if !moduleMode { if got != expect {
for _, arg := range args { t.Errorf("definition %v failed with %#v expected:\n%s\ngot:\n%s", tag, args, expect, got)
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)
} }
continue
} }
guruArgs := []string{}
if mode&jsonGoDef != 0 {
guruArgs = append(guruArgs, "-json")
} }
if runGuru { 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 := exec.Command("guru", guruArgs...)
cmd.Env = r.data.Exported.Config.Env cmd.Env = r.data.Exported.Config.Env
out, err := cmd.CombinedOutput() out, _ := cmd.Output()
if err != nil { if err != nil {
t.Errorf("Could not run guru %v: %v\n%s", guruArgs, err, out) if _, ok := err.(*exec.ExitError); !ok {
} else { return nil, fmt.Errorf("Could not run guru %v: %v\n%s", guruArgs, err, out)
guru := strings.TrimSpace(string(out)) }
if !pattern.matches(guru) { }
t.Errorf("definition %v\nexpected:\n%s\nguru gave:\n%s", args, pattern, guru) 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) { expect := string(r.data.Golden(tag, filename, func() ([]byte, error) {
cmd := exec.Command("gofmt", args...) cmd := exec.Command("gofmt", args...)
contents, _ := cmd.Output() // ignore error, sometimes we have intentionally ungofmt-able files 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 return contents, nil
})) }))
if expect == "" { if expect == "" {
@ -46,7 +46,7 @@ func (r *runner) Format(t *testing.T, data tests.Formats) {
got := captureStdOut(t, func() { got := captureStdOut(t, func() {
tool.Main(context.Background(), app, append([]string{"-remote=internal", "format"}, args...)) 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 // check the first two lines are the expected file header
if expect != got { if expect != got {
t.Errorf("format failed with %#v expected:\n%s\ngot:\n%s", args, 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 #!/bin/bash
find ./internal/lsp/ -name *.golden -delete 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 -- -- Random-hover --
func Random() int 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 -- -- Random2-hover --
func Random2(y int) int 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 -- -- err-hover --
var err error 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}") godef(aStructType, Thing)
definition(aStructType, "-emulate=guru", Thing, "$file:$line:$col: defined here as type Thing") godef(aMember, Member)
godef(aVar, Other)
definition(aMember, "", Member, "$file:$line:$col-$ecol: defined here as field Member string") godef(aFunc, Things)
definition(aMember, "-emulate=guru", Member, "$file:$line:$col: defined here as field Member string") godef(aMethod, Method)
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")
//param //param
//package name //package name
//const //const
//anon field //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 -- -- PosSum-hover --
func (*Pos).Sum() int 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 -- -- PosX-hover --
field x int 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 -- -- RandomParamY-hover --
var y int 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 -- -- A-hover --
type a.A string 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 -- -- AImport-hover --
package a ("golang.org/x/tools/internal/lsp/godef/a") 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 -- -- 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 -- -- S1-hover --
type S1 struct{F1 int; S2; a.A} 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 -- -- S1F1-hover --
field F1 int 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 -- -- S1S2-hover --
field S2 S2 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 -- -- S2-hover --
type S2 struct{F1 string; F2 int; *a.A} 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 -- -- S2F1-hover --
field F1 string 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 -- -- S2F2-hover --
field F2 int 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 -- -- Stuff-hover --
func a.Stuff() 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 -- -- S1-hover --
type S1 struct{F1 int; S2; a.A} 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 -- -- S1F1-hover --
field F1 int 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}") godef(bStructType, Thing)
definition(bStructType, "-emulate=guru", Thing, "$file:$line:$col: defined here as type $$a.Thing") godef(bMember, Member)
godef(bVar, Other)
definition(bMember, "", Member, "$file:$line:$col-$ecol: defined here as field Member string") godef(bFunc, Things)
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")
*/ */

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 -- -- myUnclosedIf-hover --
var myUnclosedIf string var myUnclosedIf string

View File

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