go/packages/packagestest: convert to the span library

Change-Id: Ib8984dd0828e3bb0b49eaa1604649300a4d54306
Reviewed-on: https://go-review.googlesource.com/c/tools/+/168900
Reviewed-by: Michael Matloob <matloob@golang.org>
diff --git a/go/packages/packagestest/expect.go b/go/packages/packagestest/expect.go
index 30f4235..925e417 100644
--- a/go/packages/packagestest/expect.go
+++ b/go/packages/packagestest/expect.go
@@ -13,6 +13,7 @@
 
 	"golang.org/x/tools/go/expect"
 	"golang.org/x/tools/go/packages"
+	"golang.org/x/tools/internal/span"
 )
 
 const (
@@ -116,15 +117,14 @@
 	return nil
 }
 
-type Range struct {
-	Start token.Pos
-	End   token.Pos
-}
+// Range is a type alias for span.Range for backwards compatability, prefer
+// using span.Range directly.
+type Range = span.Range
 
 // Mark adds a new marker to the known set.
 func (e *Exported) Mark(name string, r Range) {
 	if e.markers == nil {
-		e.markers = make(map[string]Range)
+		e.markers = make(map[string]span.Range)
 	}
 	e.markers[name] = r
 }
@@ -166,7 +166,7 @@
 		return nil
 	}
 	// set markers early so that we don't call getMarkers again from Expect
-	e.markers = make(map[string]Range)
+	e.markers = make(map[string]span.Range)
 	return e.Expect(map[string]interface{}{
 		markMethod: e.Mark,
 	})
@@ -177,7 +177,8 @@
 	identifierType = reflect.TypeOf(expect.Identifier(""))
 	posType        = reflect.TypeOf(token.Pos(0))
 	positionType   = reflect.TypeOf(token.Position{})
-	rangeType      = reflect.TypeOf(Range{})
+	rangeType      = reflect.TypeOf(span.Range{})
+	spanType       = reflect.TypeOf(span.Span{})
 	fsetType       = reflect.TypeOf((*token.FileSet)(nil))
 	regexType      = reflect.TypeOf((*regexp.Regexp)(nil))
 	exportedType   = reflect.TypeOf((*Exported)(nil))
@@ -239,6 +240,18 @@
 			}
 			return reflect.ValueOf(r), remains, nil
 		}, nil
+	case pt == spanType:
+		return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) {
+			r, remains, err := e.rangeConverter(n, args)
+			if err != nil {
+				return reflect.Value{}, nil, err
+			}
+			spn, err := r.Span()
+			if err != nil {
+				return reflect.Value{}, nil, err
+			}
+			return reflect.ValueOf(spn), remains, nil
+		}, nil
 	case pt == identifierType:
 		return func(n *expect.Note, args []interface{}) (reflect.Value, []interface{}, error) {
 			if len(args) < 1 {
@@ -340,9 +353,9 @@
 	}
 }
 
-func (e *Exported) rangeConverter(n *expect.Note, args []interface{}) (Range, []interface{}, error) {
+func (e *Exported) rangeConverter(n *expect.Note, args []interface{}) (span.Range, []interface{}, error) {
 	if len(args) < 1 {
-		return Range{}, nil, fmt.Errorf("missing argument")
+		return span.Range{}, nil, fmt.Errorf("missing argument")
 	}
 	arg := args[0]
 	args = args[1:]
@@ -354,34 +367,34 @@
 			// end of file identifier, look up the current file
 			f := e.fset.File(n.Pos)
 			eof := f.Pos(f.Size())
-			return Range{Start: eof, End: token.NoPos}, args, nil
+			return span.Range{FileSet: e.fset, Start: eof, End: token.NoPos}, args, nil
 		default:
 			// look up an marker by name
 			mark, ok := e.markers[string(arg)]
 			if !ok {
-				return Range{}, nil, fmt.Errorf("cannot find marker %v", arg)
+				return span.Range{}, nil, fmt.Errorf("cannot find marker %v", arg)
 			}
 			return mark, args, nil
 		}
 	case string:
 		start, end, err := expect.MatchBefore(e.fset, e.FileContents, n.Pos, arg)
 		if err != nil {
-			return Range{}, nil, err
+			return span.Range{}, nil, err
 		}
 		if start == token.NoPos {
-			return Range{}, nil, fmt.Errorf("%v: pattern %s did not match", e.fset.Position(n.Pos), arg)
+			return span.Range{}, nil, fmt.Errorf("%v: pattern %s did not match", e.fset.Position(n.Pos), arg)
 		}
-		return Range{Start: start, End: end}, args, nil
+		return span.Range{FileSet: e.fset, Start: start, End: end}, args, nil
 	case *regexp.Regexp:
 		start, end, err := expect.MatchBefore(e.fset, e.FileContents, n.Pos, arg)
 		if err != nil {
-			return Range{}, nil, err
+			return span.Range{}, nil, err
 		}
 		if start == token.NoPos {
-			return Range{}, nil, fmt.Errorf("%v: pattern %s did not match", e.fset.Position(n.Pos), arg)
+			return span.Range{}, nil, fmt.Errorf("%v: pattern %s did not match", e.fset.Position(n.Pos), arg)
 		}
-		return Range{Start: start, End: end}, args, nil
+		return span.Range{FileSet: e.fset, Start: start, End: end}, args, nil
 	default:
-		return Range{}, nil, fmt.Errorf("cannot convert %v to pos", arg)
+		return span.Range{}, nil, fmt.Errorf("cannot convert %v to pos", arg)
 	}
 }
diff --git a/go/packages/packagestest/expect_test.go b/go/packages/packagestest/expect_test.go
index a51946d..527c8d7 100644
--- a/go/packages/packagestest/expect_test.go
+++ b/go/packages/packagestest/expect_test.go
@@ -10,6 +10,7 @@
 
 	"golang.org/x/tools/go/expect"
 	"golang.org/x/tools/go/packages/packagestest"
+	"golang.org/x/tools/internal/span"
 )
 
 func TestExpect(t *testing.T) {
@@ -42,7 +43,7 @@
 			}
 		},
 		"directNote": func(n *expect.Note) {},
-		"range": func(r packagestest.Range) {
+		"range": func(r span.Range) {
 			if r.Start == token.NoPos || r.Start == 0 {
 				t.Errorf("Range had no valid starting position")
 			}
diff --git a/go/packages/packagestest/export.go b/go/packages/packagestest/export.go
index ea478a3..e927313 100644
--- a/go/packages/packagestest/export.go
+++ b/go/packages/packagestest/export.go
@@ -24,6 +24,7 @@
 
 	"golang.org/x/tools/go/expect"
 	"golang.org/x/tools/go/packages"
+	"golang.org/x/tools/internal/span"
 )
 
 var (
@@ -66,7 +67,7 @@
 	written map[string]map[string]string // the full set of exported files
 	fset    *token.FileSet               // The file set used when parsing expectations
 	notes   []*expect.Note               // The list of expectations extracted from go source files
-	markers map[string]Range             // The set of markers extracted from go source files
+	markers map[string]span.Range        // The set of markers extracted from go source files
 }
 
 // Exporter implementations are responsible for converting from the generic description of some
diff --git a/internal/lsp/cmd/definition_test.go b/internal/lsp/cmd/definition_test.go
index c19957f..e9e9cb0 100644
--- a/internal/lsp/cmd/definition_test.go
+++ b/internal/lsp/cmd/definition_test.go
@@ -8,7 +8,6 @@
 	"context"
 	"flag"
 	"fmt"
-	"go/token"
 	"io/ioutil"
 	"os"
 	"os/exec"
@@ -60,46 +59,43 @@
 	defer exported.Cleanup()
 	count := 0
 	if err := exported.Expect(map[string]interface{}{
-		"definition": func(fset *token.FileSet, src token.Pos, flags string, def packagestest.Range, match string) {
+		"definition": func(src span.Span, flags string, def span.Span, match string) {
 			count++
 			args := []string{"query"}
 			if flags != "" {
 				args = append(args, strings.Split(flags, " ")...)
 			}
 			args = append(args, "definition")
-			f := fset.File(src)
-			spn := span.New(span.FileURI(f.Name()), span.NewPoint(0, 0, f.Offset(src)), span.Point{})
-			args = append(args, fmt.Sprint(spn))
+			args = append(args, fmt.Sprint(src))
 			app := &cmd.Application{}
 			app.Config = *exported.Config
 			got := captureStdOut(t, func() {
 				tool.Main(context.Background(), app, args)
 			})
-			start := fset.Position(def.Start)
-			end := fset.Position(def.End)
 			expect := os.Expand(match, func(name string) string {
 				switch name {
 				case "file":
-					return start.Filename
+					fname, _ := def.URI().Filename()
+					return fname
 				case "efile":
-					qfile := strconv.Quote(start.Filename)
+					fname, _ := def.URI().Filename()
+					qfile := strconv.Quote(fname)
 					return qfile[1 : len(qfile)-1]
 				case "euri":
-					uri := span.FileURI(start.Filename)
-					quri := strconv.Quote(string(uri))
+					quri := strconv.Quote(string(def.URI()))
 					return quri[1 : len(quri)-1]
 				case "line":
-					return fmt.Sprint(start.Line)
+					return fmt.Sprint(def.Start().Line())
 				case "col":
-					return fmt.Sprint(start.Column)
+					return fmt.Sprint(def.Start().Column())
 				case "offset":
-					return fmt.Sprint(start.Offset)
+					return fmt.Sprint(def.Start().Offset())
 				case "eline":
-					return fmt.Sprint(end.Line)
+					return fmt.Sprint(def.End().Line())
 				case "ecol":
-					return fmt.Sprint(end.Column)
+					return fmt.Sprint(def.End().Column())
 				case "eoffset":
-					return fmt.Sprint(end.Offset)
+					return fmt.Sprint(def.End().Offset())
 				default:
 					return name
 				}