diff --git a/internal/lsp/cmd/cmd_test.go b/internal/lsp/cmd/cmd_test.go index f91f359812..5474238049 100644 --- a/internal/lsp/cmd/cmd_test.go +++ b/internal/lsp/cmd/cmd_test.go @@ -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 { diff --git a/internal/lsp/cmd/definition_test.go b/internal/lsp/cmd/definition_test.go index 3e44f9a208..e7ba04a69b 100644 --- a/internal/lsp/cmd/definition_test.go +++ b/internal/lsp/cmd/definition_test.go @@ -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 -} diff --git a/internal/lsp/cmd/format_test.go b/internal/lsp/cmd/format_test.go index 8e380757d8..5674fa4ca5 100644 --- a/internal/lsp/cmd/format_test.go +++ b/internal/lsp/cmd/format_test.go @@ -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) diff --git a/internal/lsp/reset_golden.sh b/internal/lsp/reset_golden.sh index d52ee428cc..9439ed0b39 100755 --- a/internal/lsp/reset_golden.sh +++ b/internal/lsp/reset_golden.sh @@ -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 diff --git a/internal/lsp/testdata/godef/a/a.go.golden b/internal/lsp/testdata/godef/a/a.go.golden index be397359ba..c3cc488389 100644 --- a/internal/lsp/testdata/godef/a/a.go.golden +++ b/internal/lsp/testdata/godef/a/a.go.golden @@ -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 diff --git a/internal/lsp/testdata/godef/a/d.go b/internal/lsp/testdata/godef/a/d.go index 0b1498e64a..4025788c8d 100644 --- a/internal/lsp/testdata/godef/a/d.go +++ b/internal/lsp/testdata/godef/a/d.go @@ -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$$" -}`) */ diff --git a/internal/lsp/testdata/godef/a/d.go.golden b/internal/lsp/testdata/godef/a/d.go.golden new file mode 100644 index 0000000000..6e3a2bdc02 --- /dev/null +++ b/internal/lsp/testdata/godef/a/d.go.golden @@ -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 diff --git a/internal/lsp/testdata/godef/a/random.go.golden b/internal/lsp/testdata/godef/a/random.go.golden index b702ee84db..077b710673 100644 --- a/internal/lsp/testdata/godef/a/random.go.golden +++ b/internal/lsp/testdata/godef/a/random.go.golden @@ -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 diff --git a/internal/lsp/testdata/godef/b/b.go.golden b/internal/lsp/testdata/godef/b/b.go.golden index 5fae42705d..556337e580 100644 --- a/internal/lsp/testdata/godef/b/b.go.golden +++ b/internal/lsp/testdata/godef/b/b.go.golden @@ -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() diff --git a/internal/lsp/testdata/godef/b/c.go.golden b/internal/lsp/testdata/godef/b/c.go.golden index 6d86d7388b..69a14ebc0e 100644 --- a/internal/lsp/testdata/godef/b/c.go.golden +++ b/internal/lsp/testdata/godef/b/c.go.golden @@ -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 diff --git a/internal/lsp/testdata/godef/b/e.go b/internal/lsp/testdata/godef/b/e.go index 6b2337a8da..dc8fe6e284 100644 --- a/internal/lsp/testdata/godef/b/e.go +++ b/internal/lsp/testdata/godef/b/e.go @@ -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) */ diff --git a/internal/lsp/testdata/godef/b/e.go.golden b/internal/lsp/testdata/godef/b/e.go.golden new file mode 100644 index 0000000000..5db0e4c6a6 --- /dev/null +++ b/internal/lsp/testdata/godef/b/e.go.golden @@ -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 diff --git a/internal/lsp/testdata/godef/broken/unclosedIf.go.golden b/internal/lsp/testdata/godef/broken/unclosedIf.go.golden index 47af5862bc..e49297a5e6 100644 --- a/internal/lsp/testdata/godef/broken/unclosedIf.go.golden +++ b/internal/lsp/testdata/godef/broken/unclosedIf.go.golden @@ -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 diff --git a/internal/lsp/tests/tests.go b/internal/lsp/tests/tests.go index 595ebcc455..e099f69597 100644 --- a/internal/lsp/tests/tests.go +++ b/internal/lsp/tests/tests.go @@ -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 {