mirror of
https://github.com/golang/go.git
synced 2025-05-07 16:43:03 +00:00
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>
This commit is contained in:
parent
a27f5b3448
commit
dce4131cda
@ -184,6 +184,8 @@ func (r *calleesResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
|||||||
res.Callees = j
|
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
|
type byFuncPos []*ssa.Function
|
||||||
|
|
||||||
func (a byFuncPos) Len() int { return len(a) }
|
func (a byFuncPos) Len() int { return len(a) }
|
||||||
|
@ -190,12 +190,12 @@ func (r *implementsResult) display(printf printfFunc) {
|
|||||||
|
|
||||||
if isInterface(r.t) {
|
if isInterface(r.t) {
|
||||||
if types.NewMethodSet(r.t).Len() == 0 { // TODO(adonovan): cache mset
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.method == nil {
|
if r.method == nil {
|
||||||
printf(r.pos, "interface type %s", r.t)
|
printf(r.pos, "interface type %s", r.qpos.typeString(r.t))
|
||||||
} else {
|
} else {
|
||||||
printf(r.method, "abstract method %s", r.qpos.objectString(r.method))
|
printf(r.method, "abstract method %s", r.qpos.objectString(r.method))
|
||||||
}
|
}
|
||||||
@ -205,7 +205,7 @@ func (r *implementsResult) display(printf printfFunc) {
|
|||||||
if !isInterface(sub) {
|
if !isInterface(sub) {
|
||||||
if r.method == nil {
|
if r.method == nil {
|
||||||
printf(deref(sub).(*types.Named).Obj(), "\t%s %s type %s",
|
printf(deref(sub).(*types.Named).Obj(), "\t%s %s type %s",
|
||||||
relation, typeKind(sub), sub)
|
relation, typeKind(sub), r.qpos.typeString(sub))
|
||||||
} else {
|
} else {
|
||||||
meth(r.toMethod[i])
|
meth(r.toMethod[i])
|
||||||
}
|
}
|
||||||
@ -215,7 +215,7 @@ func (r *implementsResult) display(printf printfFunc) {
|
|||||||
if isInterface(sub) {
|
if isInterface(sub) {
|
||||||
if r.method == nil {
|
if r.method == nil {
|
||||||
printf(sub.(*types.Named).Obj(), "\t%s %s type %s",
|
printf(sub.(*types.Named).Obj(), "\t%s %s type %s",
|
||||||
relation, typeKind(sub), sub)
|
relation, typeKind(sub), r.qpos.typeString(sub))
|
||||||
} else {
|
} else {
|
||||||
meth(r.toMethod[i])
|
meth(r.toMethod[i])
|
||||||
}
|
}
|
||||||
@ -225,7 +225,8 @@ func (r *implementsResult) display(printf printfFunc) {
|
|||||||
relation = "implements"
|
relation = "implements"
|
||||||
for i, super := range r.from {
|
for i, super := range r.from {
|
||||||
if r.method == nil {
|
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 {
|
} else {
|
||||||
meth(r.fromMethod[i])
|
meth(r.fromMethod[i])
|
||||||
}
|
}
|
||||||
@ -235,7 +236,8 @@ func (r *implementsResult) display(printf printfFunc) {
|
|||||||
|
|
||||||
if r.from != nil {
|
if r.from != nil {
|
||||||
if r.method == 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 {
|
} else {
|
||||||
printf(r.method, "concrete method %s",
|
printf(r.method, "concrete method %s",
|
||||||
r.qpos.objectString(r.method))
|
r.qpos.objectString(r.method))
|
||||||
@ -243,7 +245,7 @@ func (r *implementsResult) display(printf printfFunc) {
|
|||||||
for i, super := range r.from {
|
for i, super := range r.from {
|
||||||
if r.method == nil {
|
if r.method == nil {
|
||||||
printf(super.(*types.Named).Obj(), "\t%s %s",
|
printf(super.(*types.Named).Obj(), "\t%s %s",
|
||||||
relation, super)
|
relation, r.qpos.typeString(super))
|
||||||
} else {
|
} else {
|
||||||
meth(r.fromMethod[i])
|
meth(r.fromMethod[i])
|
||||||
}
|
}
|
||||||
@ -251,7 +253,7 @@ func (r *implementsResult) display(printf printfFunc) {
|
|||||||
}
|
}
|
||||||
if r.fromPtr != nil {
|
if r.fromPtr != nil {
|
||||||
if r.method == 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 {
|
} else {
|
||||||
// TODO(adonovan): de-dup (C).f and (*C).f implementing (I).f.
|
// TODO(adonovan): de-dup (C).f and (*C).f implementing (I).f.
|
||||||
printf(r.method, "concrete method %s",
|
printf(r.method, "concrete method %s",
|
||||||
@ -261,13 +263,14 @@ func (r *implementsResult) display(printf printfFunc) {
|
|||||||
for i, psuper := range r.fromPtr {
|
for i, psuper := range r.fromPtr {
|
||||||
if r.method == nil {
|
if r.method == nil {
|
||||||
printf(psuper.(*types.Named).Obj(), "\t%s %s",
|
printf(psuper.(*types.Named).Obj(), "\t%s %s",
|
||||||
relation, psuper)
|
relation, r.qpos.typeString(psuper))
|
||||||
} else {
|
} else {
|
||||||
meth(r.fromPtrMethod[i])
|
meth(r.fromPtrMethod[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if r.from == nil {
|
} 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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,6 +211,7 @@ func TestOracle(t *testing.T) {
|
|||||||
"testdata/src/imports/main.go",
|
"testdata/src/imports/main.go",
|
||||||
"testdata/src/peers/main.go",
|
"testdata/src/peers/main.go",
|
||||||
"testdata/src/pointsto/main.go",
|
"testdata/src/pointsto/main.go",
|
||||||
|
"testdata/src/referrers/main.go",
|
||||||
"testdata/src/reflection/main.go",
|
"testdata/src/reflection/main.go",
|
||||||
"testdata/src/what/main.go",
|
"testdata/src/what/main.go",
|
||||||
"testdata/src/whicherrs/main.go",
|
"testdata/src/whicherrs/main.go",
|
||||||
|
@ -243,6 +243,8 @@ func (r *peersResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
|||||||
|
|
||||||
// -------- utils --------
|
// -------- 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
|
type byPos []token.Pos
|
||||||
|
|
||||||
func (p byPos) Len() int { return len(p) }
|
func (p byPos) Len() int { return len(p) }
|
||||||
|
@ -90,7 +90,7 @@ func referrers(q *Query) error {
|
|||||||
}
|
}
|
||||||
allowErrors(&lconf)
|
allowErrors(&lconf)
|
||||||
for path := range rev.Search(obj.Pkg().Path()) {
|
for path := range rev.Search(obj.Pkg().Path()) {
|
||||||
lconf.Import(path)
|
lconf.ImportWithTests(path)
|
||||||
}
|
}
|
||||||
pass2 = true
|
pass2 = true
|
||||||
}
|
}
|
||||||
@ -104,9 +104,7 @@ func referrers(q *Query) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO(adonovan): is this sort stable? Pos order depends on
|
sort.Sort(byNamePos{q.Fset, refs})
|
||||||
// when packages are reached. Use filename order?
|
|
||||||
sort.Sort(byNamePos(refs))
|
|
||||||
|
|
||||||
q.result = &referrersResult{
|
q.result = &referrersResult{
|
||||||
fset: q.Fset,
|
fset: q.Fset,
|
||||||
@ -134,11 +132,27 @@ func sameObj(x, y types.Object) bool {
|
|||||||
|
|
||||||
// -------- utils --------
|
// -------- 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) }
|
type byNamePos struct {
|
||||||
func (p byNamePos) Less(i, j int) bool { return p[i].NamePos < p[j].NamePos }
|
fset *token.FileSet
|
||||||
func (p byNamePos) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
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 {
|
type referrersResult struct {
|
||||||
fset *token.FileSet
|
fset *token.FileSet
|
||||||
|
42
oracle/testdata/src/implements/main.golden
vendored
42
oracle/testdata/src/implements/main.golden
vendored
@ -1,44 +1,44 @@
|
|||||||
-------- @implements E --------
|
-------- @implements E --------
|
||||||
empty interface type implements.E
|
empty interface type E
|
||||||
|
|
||||||
-------- @implements F --------
|
-------- @implements F --------
|
||||||
interface type implements.F
|
interface type F
|
||||||
is implemented by pointer type *implements.C
|
is implemented by pointer type *C
|
||||||
is implemented by struct type implements.D
|
is implemented by struct type D
|
||||||
is implemented by interface type implements.FG
|
is implemented by interface type FG
|
||||||
|
|
||||||
-------- @implements FG --------
|
-------- @implements FG --------
|
||||||
interface type implements.FG
|
interface type FG
|
||||||
is implemented by pointer type *implements.D
|
is implemented by pointer type *D
|
||||||
implements implements.F
|
implements F
|
||||||
|
|
||||||
-------- @implements slice --------
|
-------- @implements slice --------
|
||||||
slice type []int implements only interface{}
|
slice type []int implements only interface{}
|
||||||
|
|
||||||
-------- @implements C --------
|
-------- @implements C --------
|
||||||
pointer type *implements.C
|
pointer type *C
|
||||||
implements implements.F
|
implements F
|
||||||
|
|
||||||
-------- @implements starC --------
|
-------- @implements starC --------
|
||||||
pointer type *implements.C
|
pointer type *C
|
||||||
implements implements.F
|
implements F
|
||||||
|
|
||||||
-------- @implements D --------
|
-------- @implements D --------
|
||||||
struct type implements.D
|
struct type D
|
||||||
implements implements.F
|
implements F
|
||||||
pointer type *implements.D
|
pointer type *D
|
||||||
implements implements.FG
|
implements FG
|
||||||
|
|
||||||
-------- @implements starD --------
|
-------- @implements starD --------
|
||||||
pointer type *implements.D
|
pointer type *D
|
||||||
implements implements.F
|
implements F
|
||||||
implements implements.FG
|
implements FG
|
||||||
|
|
||||||
-------- @implements sorter --------
|
-------- @implements sorter --------
|
||||||
slice type implements.sorter
|
slice type sorter
|
||||||
implements lib.Sorter
|
implements lib.Sorter
|
||||||
|
|
||||||
-------- @implements I --------
|
-------- @implements I --------
|
||||||
interface type implements.I
|
interface type I
|
||||||
is implemented by basic type lib.Type
|
is implemented by basic type lib.Type
|
||||||
|
|
||||||
|
@ -19,9 +19,13 @@
|
|||||||
"objpos": "testdata/src/lib/lib.go:5:13",
|
"objpos": "testdata/src/lib/lib.go:5:13",
|
||||||
"desc": "func (lib.Type).Method(x *int) *int",
|
"desc": "func (lib.Type).Method(x *int) *int",
|
||||||
"refs": [
|
"refs": [
|
||||||
|
"testdata/src/imports/main.go:22:9",
|
||||||
"testdata/src/referrers-json/main.go:15:8",
|
"testdata/src/referrers-json/main.go:15:8",
|
||||||
"testdata/src/referrers-json/main.go:16: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"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
8
oracle/testdata/src/referrers/ext_test.go
vendored
Normal file
8
oracle/testdata/src/referrers/ext_test.go
vendored
Normal file
@ -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
|
||||||
|
}
|
8
oracle/testdata/src/referrers/int_test.go
vendored
Normal file
8
oracle/testdata/src/referrers/int_test.go
vendored
Normal file
@ -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
|
||||||
|
}
|
24
oracle/testdata/src/referrers/main.go
vendored
Normal file
24
oracle/testdata/src/referrers/main.go
vendored
Normal file
@ -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
|
||||||
|
}
|
27
oracle/testdata/src/referrers/main.golden
vendored
Normal file
27
oracle/testdata/src/referrers/main.golden
vendored
Normal file
@ -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
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user