oracle: referrers: also scan *_test.go files for references.

Added test case.  This required making the result sort order
deterministic when the results are spread across several packages.

Also: implements: print type names relative to query package.
Updated tests.

Change-Id: I9f882cd358a612585a4aac9a117b89d9131a294e
Reviewed-on: https://go-review.googlesource.com/8283
Reviewed-by: David Crawshaw <crawshaw@golang.org>
diff --git a/oracle/callees.go b/oracle/callees.go
index ee1d432..4bad1f0 100644
--- a/oracle/callees.go
+++ b/oracle/callees.go
@@ -184,6 +184,8 @@
 	res.Callees = j
 }
 
+// NB: byFuncPos is not deterministic across packages since it depends on load order.
+// Use lessPos if the tests need it.
 type byFuncPos []*ssa.Function
 
 func (a byFuncPos) Len() int           { return len(a) }
diff --git a/oracle/implements.go b/oracle/implements.go
index 9af2269..156416d 100644
--- a/oracle/implements.go
+++ b/oracle/implements.go
@@ -190,12 +190,12 @@
 
 	if isInterface(r.t) {
 		if types.NewMethodSet(r.t).Len() == 0 { // TODO(adonovan): cache mset
-			printf(r.pos, "empty interface type %s", r.t)
+			printf(r.pos, "empty interface type %s", r.qpos.typeString(r.t))
 			return
 		}
 
 		if r.method == nil {
-			printf(r.pos, "interface type %s", r.t)
+			printf(r.pos, "interface type %s", r.qpos.typeString(r.t))
 		} else {
 			printf(r.method, "abstract method %s", r.qpos.objectString(r.method))
 		}
@@ -205,7 +205,7 @@
 			if !isInterface(sub) {
 				if r.method == nil {
 					printf(deref(sub).(*types.Named).Obj(), "\t%s %s type %s",
-						relation, typeKind(sub), sub)
+						relation, typeKind(sub), r.qpos.typeString(sub))
 				} else {
 					meth(r.toMethod[i])
 				}
@@ -215,7 +215,7 @@
 			if isInterface(sub) {
 				if r.method == nil {
 					printf(sub.(*types.Named).Obj(), "\t%s %s type %s",
-						relation, typeKind(sub), sub)
+						relation, typeKind(sub), r.qpos.typeString(sub))
 				} else {
 					meth(r.toMethod[i])
 				}
@@ -225,7 +225,8 @@
 		relation = "implements"
 		for i, super := range r.from {
 			if r.method == nil {
-				printf(super.(*types.Named).Obj(), "\t%s %s", relation, super)
+				printf(super.(*types.Named).Obj(), "\t%s %s",
+					relation, r.qpos.typeString(super))
 			} else {
 				meth(r.fromMethod[i])
 			}
@@ -235,7 +236,8 @@
 
 		if r.from != nil {
 			if r.method == nil {
-				printf(r.pos, "%s type %s", typeKind(r.t), r.t)
+				printf(r.pos, "%s type %s",
+					typeKind(r.t), r.qpos.typeString(r.t))
 			} else {
 				printf(r.method, "concrete method %s",
 					r.qpos.objectString(r.method))
@@ -243,7 +245,7 @@
 			for i, super := range r.from {
 				if r.method == nil {
 					printf(super.(*types.Named).Obj(), "\t%s %s",
-						relation, super)
+						relation, r.qpos.typeString(super))
 				} else {
 					meth(r.fromMethod[i])
 				}
@@ -251,7 +253,7 @@
 		}
 		if r.fromPtr != nil {
 			if r.method == nil {
-				printf(r.pos, "pointer type *%s", r.t)
+				printf(r.pos, "pointer type *%s", r.qpos.typeString(r.t))
 			} else {
 				// TODO(adonovan): de-dup (C).f and (*C).f implementing (I).f.
 				printf(r.method, "concrete method %s",
@@ -261,13 +263,14 @@
 			for i, psuper := range r.fromPtr {
 				if r.method == nil {
 					printf(psuper.(*types.Named).Obj(), "\t%s %s",
-						relation, psuper)
+						relation, r.qpos.typeString(psuper))
 				} else {
 					meth(r.fromPtrMethod[i])
 				}
 			}
 		} else if r.from == nil {
-			printf(r.pos, "%s type %s implements only interface{}", typeKind(r.t), r.t)
+			printf(r.pos, "%s type %s implements only interface{}",
+				typeKind(r.t), r.qpos.typeString(r.t))
 		}
 	}
 }
diff --git a/oracle/oracle_test.go b/oracle/oracle_test.go
index 977d075..f1353c7 100644
--- a/oracle/oracle_test.go
+++ b/oracle/oracle_test.go
@@ -211,6 +211,7 @@
 		"testdata/src/imports/main.go",
 		"testdata/src/peers/main.go",
 		"testdata/src/pointsto/main.go",
+		"testdata/src/referrers/main.go",
 		"testdata/src/reflection/main.go",
 		"testdata/src/what/main.go",
 		"testdata/src/whicherrs/main.go",
diff --git a/oracle/peers.go b/oracle/peers.go
index 350159c..a6c9ece 100644
--- a/oracle/peers.go
+++ b/oracle/peers.go
@@ -243,6 +243,8 @@
 
 // -------- utils --------
 
+// NB: byPos is not deterministic across packages since it depends on load order.
+// Use lessPos if the tests need it.
 type byPos []token.Pos
 
 func (p byPos) Len() int           { return len(p) }
diff --git a/oracle/referrers.go b/oracle/referrers.go
index af334af..0485950 100644
--- a/oracle/referrers.go
+++ b/oracle/referrers.go
@@ -90,7 +90,7 @@
 		}
 		allowErrors(&lconf)
 		for path := range rev.Search(obj.Pkg().Path()) {
-			lconf.Import(path)
+			lconf.ImportWithTests(path)
 		}
 		pass2 = true
 	}
@@ -104,9 +104,7 @@
 			}
 		}
 	}
-	// TODO(adonovan): is this sort stable?  Pos order depends on
-	// when packages are reached.  Use filename order?
-	sort.Sort(byNamePos(refs))
+	sort.Sort(byNamePos{q.Fset, refs})
 
 	q.result = &referrersResult{
 		fset:  q.Fset,
@@ -134,11 +132,27 @@
 
 // -------- utils --------
 
-type byNamePos []*ast.Ident
+// An deterministic ordering for token.Pos that doesn't
+// depend on the order in which packages were loaded.
+func lessPos(fset *token.FileSet, x, y token.Pos) bool {
+	fx := fset.File(x)
+	fy := fset.File(y)
+	if fx != fy {
+		return fx.Name() < fy.Name()
+	}
+	return x < y
+}
 
-func (p byNamePos) Len() int           { return len(p) }
-func (p byNamePos) Less(i, j int) bool { return p[i].NamePos < p[j].NamePos }
-func (p byNamePos) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
+type byNamePos struct {
+	fset *token.FileSet
+	ids  []*ast.Ident
+}
+
+func (p byNamePos) Len() int      { return len(p.ids) }
+func (p byNamePos) Swap(i, j int) { p.ids[i], p.ids[j] = p.ids[j], p.ids[i] }
+func (p byNamePos) Less(i, j int) bool {
+	return lessPos(p.fset, p.ids[i].NamePos, p.ids[j].NamePos)
+}
 
 type referrersResult struct {
 	fset  *token.FileSet
diff --git a/oracle/testdata/src/implements/main.golden b/oracle/testdata/src/implements/main.golden
index 99dfe6d..ee00f3d 100644
--- a/oracle/testdata/src/implements/main.golden
+++ b/oracle/testdata/src/implements/main.golden
@@ -1,44 +1,44 @@
 -------- @implements E --------
-empty interface type implements.E
+empty interface type E
 
 -------- @implements F --------
-interface type implements.F
-	is implemented by pointer type *implements.C
-	is implemented by struct type implements.D
-	is implemented by interface type implements.FG
+interface type F
+	is implemented by pointer type *C
+	is implemented by struct type D
+	is implemented by interface type FG
 
 -------- @implements FG --------
-interface type implements.FG
-	is implemented by pointer type *implements.D
-	implements implements.F
+interface type FG
+	is implemented by pointer type *D
+	implements F
 
 -------- @implements slice --------
 slice type []int implements only interface{}
 
 -------- @implements C --------
-pointer type *implements.C
-	implements implements.F
+pointer type *C
+	implements F
 
 -------- @implements starC --------
-pointer type *implements.C
-	implements implements.F
+pointer type *C
+	implements F
 
 -------- @implements D --------
-struct type implements.D
-	implements implements.F
-pointer type *implements.D
-	implements implements.FG
+struct type D
+	implements F
+pointer type *D
+	implements FG
 
 -------- @implements starD --------
-pointer type *implements.D
-	implements implements.F
-	implements implements.FG
+pointer type *D
+	implements F
+	implements FG
 
 -------- @implements sorter --------
-slice type implements.sorter
+slice type sorter
 	implements lib.Sorter
 
 -------- @implements I --------
-interface type implements.I
+interface type I
 	is implemented by basic type lib.Type
 
diff --git a/oracle/testdata/src/referrers-json/main.golden b/oracle/testdata/src/referrers-json/main.golden
index 9d65222..239620c 100644
--- a/oracle/testdata/src/referrers-json/main.golden
+++ b/oracle/testdata/src/referrers-json/main.golden
@@ -19,9 +19,13 @@
 		"objpos": "testdata/src/lib/lib.go:5:13",
 		"desc": "func (lib.Type).Method(x *int) *int",
 		"refs": [
+			"testdata/src/imports/main.go:22:9",
 			"testdata/src/referrers-json/main.go:15:8",
 			"testdata/src/referrers-json/main.go:16:8",
-			"testdata/src/imports/main.go:22:9"
+			"testdata/src/referrers/ext_test.go:7:17",
+			"testdata/src/referrers/int_test.go:7:17",
+			"testdata/src/referrers/main.go:15:8",
+			"testdata/src/referrers/main.go:16:8"
 		]
 	}
 }
diff --git a/oracle/testdata/src/referrers/ext_test.go b/oracle/testdata/src/referrers/ext_test.go
new file mode 100644
index 0000000..d507e80
--- /dev/null
+++ b/oracle/testdata/src/referrers/ext_test.go
@@ -0,0 +1,8 @@
+package main_test
+
+import "lib"
+
+func _() {
+	// This reference should be found by the ref-method query.
+	_ = (lib.Type).Method // ref from external test package
+}
diff --git a/oracle/testdata/src/referrers/int_test.go b/oracle/testdata/src/referrers/int_test.go
new file mode 100644
index 0000000..9102cd6
--- /dev/null
+++ b/oracle/testdata/src/referrers/int_test.go
@@ -0,0 +1,8 @@
+package main
+
+import "lib"
+
+func _() {
+	// This reference should be found by the ref-method query.
+	_ = (lib.Type).Method // ref from internal test package
+}
diff --git a/oracle/testdata/src/referrers/main.go b/oracle/testdata/src/referrers/main.go
new file mode 100644
index 0000000..f551ee0
--- /dev/null
+++ b/oracle/testdata/src/referrers/main.go
@@ -0,0 +1,24 @@
+package main
+
+// Tests of 'referrers' query.
+// See go.tools/oracle/oracle_test.go for explanation.
+// See referrers.golden for expected query results.
+
+import "lib"
+
+type s struct {
+	f int
+}
+
+func main() {
+	var v lib.Type = lib.Const // @referrers ref-package "lib"
+	_ = v.Method               // @referrers ref-method "Method"
+	_ = v.Method
+	v++ //@referrers ref-local "v"
+	v++
+
+	_ = s{}.f // @referrers ref-field "f"
+
+	var s2 s
+	s2.f = 1
+}
diff --git a/oracle/testdata/src/referrers/main.golden b/oracle/testdata/src/referrers/main.golden
new file mode 100644
index 0000000..06cab17
--- /dev/null
+++ b/oracle/testdata/src/referrers/main.golden
@@ -0,0 +1,27 @@
+-------- @referrers ref-package --------
+2 references to package lib
+	var v lib.Type = lib.Const // @referrers ref-package "lib"
+	var v lib.Type = lib.Const // @referrers ref-package "lib"
+
+-------- @referrers ref-method --------
+7 references to func (lib.Type).Method(x *int) *int
+	p := t.Method(&a)   // @describe ref-method "Method"
+	_ = v.Method               // @referrers ref-method "Method"
+	_ = v.Method
+	_ = (lib.Type).Method // ref from external test package
+	_ = (lib.Type).Method // ref from internal test package
+	_ = v.Method               // @referrers ref-method "Method"
+	_ = v.Method
+
+-------- @referrers ref-local --------
+4 references to var v lib.Type
+	_ = v.Method               // @referrers ref-method "Method"
+	_ = v.Method
+	v++ //@referrers ref-local "v"
+	v++
+
+-------- @referrers ref-field --------
+2 references to field f int
+	_ = s{}.f // @referrers ref-field "f"
+	s2.f = 1
+