oracle: when 'implements' is invoked on a method, show related methods, not types.
Fixes #9972 Change-Id: I25b65a64dcc4d551be3db8566783a9d23d410a2e Reviewed-on: https://go-review.googlesource.com/5860 Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
parent
69db398fe0
commit
264bffc00c
|
@ -59,7 +59,7 @@ The mode argument determines the query to perform:
|
|||
callstack show path from callgraph root to selected function
|
||||
describe describe selected syntax: definition, methods, etc
|
||||
freevars show free variables of selection
|
||||
implements show 'implements' relation for selected type
|
||||
implements show 'implements' relation for selected type or method
|
||||
peers show send/receive corresponding to selected channel op
|
||||
referrers show all refs to entity denoted by selected identifier
|
||||
what show basic information about the selected syntax node
|
||||
|
|
|
@ -215,13 +215,6 @@ func findInterestingNode(pkginfo *loader.PackageInfo, path []ast.Node) ([]ast.No
|
|||
return path, actionExpr
|
||||
|
||||
case *types.Func:
|
||||
// For f in 'interface {f()}', return the interface type, for now.
|
||||
if _, ok := path[1].(*ast.Field); ok {
|
||||
_ = path[2].(*ast.FieldList) // assertion
|
||||
if _, ok := path[3].(*ast.InterfaceType); ok {
|
||||
return path[3:], actionType
|
||||
}
|
||||
}
|
||||
return path, actionExpr
|
||||
|
||||
case *types.Builtin:
|
||||
|
@ -737,10 +730,14 @@ func isAccessibleFrom(obj types.Object, pkg *types.Package) bool {
|
|||
func methodsToSerial(this *types.Package, methods []*types.Selection, fset *token.FileSet) []serial.DescribeMethod {
|
||||
var jmethods []serial.DescribeMethod
|
||||
for _, meth := range methods {
|
||||
jmethods = append(jmethods, serial.DescribeMethod{
|
||||
Name: types.SelectionString(this, meth),
|
||||
Pos: fset.Position(meth.Obj().Pos()).String(),
|
||||
})
|
||||
var ser serial.DescribeMethod
|
||||
if meth != nil { // may contain nils when called by implements (on a method)
|
||||
ser = serial.DescribeMethod{
|
||||
Name: types.SelectionString(this, meth),
|
||||
Pos: fset.Position(meth.Obj().Pos()).String(),
|
||||
}
|
||||
}
|
||||
jmethods = append(jmethods, ser)
|
||||
}
|
||||
return jmethods
|
||||
}
|
||||
|
|
|
@ -17,18 +17,35 @@ import (
|
|||
)
|
||||
|
||||
// Implements displays the "implements" relation as it pertains to the
|
||||
// selected type.
|
||||
// selected type. If the selection is a method, 'implements' displays
|
||||
// the corresponding methods of the types that would have been reported
|
||||
// by an implements query on the receiver type.
|
||||
//
|
||||
func implements(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
||||
// Find the selected type.
|
||||
// TODO(adonovan): fix: make it work on qualified Idents too.
|
||||
path, action := findInterestingNode(qpos.info, qpos.path)
|
||||
if action != actionType {
|
||||
return nil, fmt.Errorf("no type here")
|
||||
|
||||
var method *types.Func
|
||||
var T types.Type // selected type (receiver if method != nil)
|
||||
|
||||
switch action {
|
||||
case actionExpr:
|
||||
// method?
|
||||
if id, ok := path[0].(*ast.Ident); ok {
|
||||
if obj, ok := qpos.info.ObjectOf(id).(*types.Func); ok {
|
||||
recv := obj.Type().(*types.Signature).Recv()
|
||||
if recv == nil {
|
||||
return nil, fmt.Errorf("this function is not a method")
|
||||
}
|
||||
method = obj
|
||||
T = recv.Type()
|
||||
}
|
||||
}
|
||||
case actionType:
|
||||
T = qpos.info.TypeOf(path[0].(ast.Expr))
|
||||
}
|
||||
T := qpos.info.TypeOf(path[0].(ast.Expr))
|
||||
if T == nil {
|
||||
return nil, fmt.Errorf("no type here")
|
||||
return nil, fmt.Errorf("no type or method here")
|
||||
}
|
||||
|
||||
// Find all named types, even local types (which can have
|
||||
|
@ -102,52 +119,128 @@ func implements(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
|||
sort.Sort(typesByString(from))
|
||||
sort.Sort(typesByString(fromPtr))
|
||||
|
||||
return &implementsResult{T, pos, to, from, fromPtr}, nil
|
||||
var toMethod, fromMethod, fromPtrMethod []*types.Selection // contain nils
|
||||
if method != nil {
|
||||
for _, t := range to {
|
||||
toMethod = append(toMethod,
|
||||
types.NewMethodSet(t).Lookup(method.Pkg(), method.Name()))
|
||||
}
|
||||
for _, t := range from {
|
||||
fromMethod = append(fromMethod,
|
||||
types.NewMethodSet(t).Lookup(method.Pkg(), method.Name()))
|
||||
}
|
||||
for _, t := range fromPtr {
|
||||
fromPtrMethod = append(fromPtrMethod,
|
||||
types.NewMethodSet(t).Lookup(method.Pkg(), method.Name()))
|
||||
}
|
||||
}
|
||||
|
||||
return &implementsResult{qpos, T, pos, to, from, fromPtr, method, toMethod, fromMethod, fromPtrMethod}, nil
|
||||
}
|
||||
|
||||
type implementsResult struct {
|
||||
qpos *QueryPos
|
||||
|
||||
t types.Type // queried type (not necessarily named)
|
||||
pos interface{} // pos of t (*types.Name or *QueryPos)
|
||||
to []types.Type // named or ptr-to-named types assignable to interface T
|
||||
from []types.Type // named interfaces assignable from T
|
||||
fromPtr []types.Type // named interfaces assignable only from *T
|
||||
|
||||
// if a method was queried:
|
||||
method *types.Func // queried method
|
||||
toMethod []*types.Selection // method of type to[i], if any
|
||||
fromMethod []*types.Selection // method of type from[i], if any
|
||||
fromPtrMethod []*types.Selection // method of type fromPtrMethod[i], if any
|
||||
}
|
||||
|
||||
func (r *implementsResult) display(printf printfFunc) {
|
||||
relation := "is implemented by"
|
||||
|
||||
meth := func(sel *types.Selection) {
|
||||
if sel != nil {
|
||||
printf(sel.Obj(), "\t%s method (%s).%s",
|
||||
relation, r.qpos.TypeString(sel.Recv()), sel.Obj().Name())
|
||||
}
|
||||
}
|
||||
|
||||
if isInterface(r.t) {
|
||||
if types.NewMethodSet(r.t).Len() == 0 { // TODO(adonovan): cache mset
|
||||
printf(r.pos, "empty interface type %s", r.t)
|
||||
return
|
||||
}
|
||||
|
||||
printf(r.pos, "interface type %s", r.t)
|
||||
// Show concrete types first; use two passes.
|
||||
for _, sub := range r.to {
|
||||
if r.method == nil {
|
||||
printf(r.pos, "interface type %s", r.t)
|
||||
} else {
|
||||
printf(r.method, "abstract method %s", r.qpos.ObjectString(r.method))
|
||||
}
|
||||
|
||||
// Show concrete types (or methods) first; use two passes.
|
||||
for i, sub := range r.to {
|
||||
if !isInterface(sub) {
|
||||
printf(deref(sub).(*types.Named).Obj(), "\tis implemented by %s type %s",
|
||||
typeKind(sub), sub)
|
||||
if r.method == nil {
|
||||
printf(deref(sub).(*types.Named).Obj(), "\t%s %s type %s",
|
||||
relation, typeKind(sub), sub)
|
||||
} else {
|
||||
meth(r.toMethod[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, sub := range r.to {
|
||||
for i, sub := range r.to {
|
||||
if isInterface(sub) {
|
||||
printf(deref(sub).(*types.Named).Obj(), "\tis implemented by %s type %s", typeKind(sub), sub)
|
||||
if r.method == nil {
|
||||
printf(sub.(*types.Named).Obj(), "\t%s %s type %s",
|
||||
relation, typeKind(sub), sub)
|
||||
} else {
|
||||
meth(r.toMethod[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, super := range r.from {
|
||||
printf(super.(*types.Named).Obj(), "\timplements %s", super)
|
||||
relation = "implements"
|
||||
for i, super := range r.from {
|
||||
if r.method == nil {
|
||||
printf(super.(*types.Named).Obj(), "\t%s %s", relation, super)
|
||||
} else {
|
||||
meth(r.fromMethod[i])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
relation = "implements"
|
||||
|
||||
if r.from != nil {
|
||||
printf(r.pos, "%s type %s", typeKind(r.t), r.t)
|
||||
for _, super := range r.from {
|
||||
printf(super.(*types.Named).Obj(), "\timplements %s", super)
|
||||
if r.method == nil {
|
||||
printf(r.pos, "%s type %s", typeKind(r.t), r.t)
|
||||
} else {
|
||||
printf(r.method, "concrete method %s",
|
||||
r.qpos.ObjectString(r.method))
|
||||
}
|
||||
for i, super := range r.from {
|
||||
if r.method == nil {
|
||||
printf(super.(*types.Named).Obj(), "\t%s %s",
|
||||
relation, super)
|
||||
} else {
|
||||
meth(r.fromMethod[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
if r.fromPtr != nil {
|
||||
printf(r.pos, "pointer type *%s", r.t)
|
||||
for _, psuper := range r.fromPtr {
|
||||
printf(psuper.(*types.Named).Obj(), "\timplements %s", psuper)
|
||||
if r.method == nil {
|
||||
printf(r.pos, "pointer type *%s", r.t)
|
||||
} else {
|
||||
// TODO(adonovan): de-dup (C).f and (*C).f implementing (I).f.
|
||||
printf(r.method, "concrete method %s",
|
||||
r.qpos.ObjectString(r.method))
|
||||
}
|
||||
|
||||
for i, psuper := range r.fromPtr {
|
||||
if r.method == nil {
|
||||
printf(psuper.(*types.Named).Obj(), "\t%s %s",
|
||||
relation, 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)
|
||||
|
@ -157,10 +250,19 @@ func (r *implementsResult) display(printf printfFunc) {
|
|||
|
||||
func (r *implementsResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||
res.Implements = &serial.Implements{
|
||||
T: makeImplementsType(r.t, fset),
|
||||
AssignableTo: makeImplementsTypes(r.to, fset),
|
||||
AssignableFrom: makeImplementsTypes(r.from, fset),
|
||||
AssignableFromPtr: makeImplementsTypes(r.fromPtr, fset),
|
||||
T: makeImplementsType(r.t, fset),
|
||||
AssignableTo: makeImplementsTypes(r.to, fset),
|
||||
AssignableFrom: makeImplementsTypes(r.from, fset),
|
||||
AssignableFromPtr: makeImplementsTypes(r.fromPtr, fset),
|
||||
AssignableToMethod: methodsToSerial(r.qpos.info.Pkg, r.toMethod, fset),
|
||||
AssignableFromMethod: methodsToSerial(r.qpos.info.Pkg, r.fromMethod, fset),
|
||||
AssignableFromPtrMethod: methodsToSerial(r.qpos.info.Pkg, r.fromPtrMethod, fset),
|
||||
}
|
||||
if r.method != nil {
|
||||
res.Implements.Method = &serial.DescribeMethod{
|
||||
Name: r.qpos.ObjectString(r.method),
|
||||
Pos: fset.Position(r.method.Pos()).String(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -208,6 +208,7 @@ func TestOracle(t *testing.T) {
|
|||
"testdata/src/main/describe.go",
|
||||
"testdata/src/main/freevars.go",
|
||||
"testdata/src/main/implements.go",
|
||||
"testdata/src/main/implements-methods.go",
|
||||
"testdata/src/main/imports.go",
|
||||
"testdata/src/main/peers.go",
|
||||
"testdata/src/main/pointsto.go",
|
||||
|
@ -221,6 +222,7 @@ func TestOracle(t *testing.T) {
|
|||
"testdata/src/main/peers-json.go",
|
||||
"testdata/src/main/describe-json.go",
|
||||
"testdata/src/main/implements-json.go",
|
||||
"testdata/src/main/implements-methods-json.go",
|
||||
"testdata/src/main/pointsto-json.go",
|
||||
"testdata/src/main/referrers-json.go",
|
||||
"testdata/src/main/what-json.go",
|
||||
|
|
|
@ -101,7 +101,6 @@ type FreeVar struct {
|
|||
}
|
||||
|
||||
// An Implements contains the result of an 'implements' query.
|
||||
|
||||
// It describes the queried type, the set of named non-empty interface
|
||||
// types to which it is assignable, and the set of named/*named types
|
||||
// (concrete or non-empty interface) which may be assigned to it.
|
||||
|
@ -111,6 +110,15 @@ type Implements struct {
|
|||
AssignableTo []ImplementsType `json:"to,omitempty"` // types assignable to T
|
||||
AssignableFrom []ImplementsType `json:"from,omitempty"` // interface types assignable from T
|
||||
AssignableFromPtr []ImplementsType `json:"fromptr,omitempty"` // interface types assignable only from *T
|
||||
|
||||
// The following fields are set only if the query was a method.
|
||||
// Assignable{To,From,FromPtr}Method[i] is the corresponding
|
||||
// method of type Assignable{To,From,FromPtr}[i], or blank
|
||||
// {"",""} if that type lacks the method.
|
||||
Method *DescribeMethod `json:"method,omitempty"` // the queried method
|
||||
AssignableToMethod []DescribeMethod `json:"to_method,omitempty"`
|
||||
AssignableFromMethod []DescribeMethod `json:"from_method,omitempty"`
|
||||
AssignableFromPtrMethod []DescribeMethod `json:"fromptr_method,omitempty"`
|
||||
}
|
||||
|
||||
// An ImplementsType describes a single type as part of an 'implements' query.
|
||||
|
|
|
@ -167,7 +167,5 @@ Method set:
|
|||
method (I) f()
|
||||
|
||||
-------- @describe def-imethod-I.f --------
|
||||
type interface{f()}
|
||||
Method set:
|
||||
method (interface{f()}) f()
|
||||
definition of interface method func (I).f()
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package main
|
||||
|
||||
// Tests of 'implements' query applied to methods, -output=json.
|
||||
// See go.tools/oracle/oracle_test.go for explanation.
|
||||
// See implements-methods.golden for expected query results.
|
||||
|
||||
import _ "lib"
|
||||
import _ "sort"
|
||||
|
||||
func main() {
|
||||
}
|
||||
|
||||
type F interface {
|
||||
f() // @implements F.f "f"
|
||||
}
|
||||
|
||||
type FG interface {
|
||||
f() // @implements FG.f "f"
|
||||
g() []int // @implements FG.g "g"
|
||||
}
|
||||
|
||||
type C int
|
||||
type D struct{}
|
||||
|
||||
func (c *C) f() {} // @implements *C.f "f"
|
||||
func (d D) f() {} // @implements D.f "f"
|
||||
|
||||
func (d *D) g() []int { return nil } // @implements *D.g "g"
|
||||
|
||||
type sorter []int
|
||||
|
||||
func (sorter) Len() int { return 0 } // @implements Len "Len"
|
||||
func (sorter) Less(i, j int) bool { return false }
|
||||
func (sorter) Swap(i, j int) {}
|
||||
|
||||
type I interface {
|
||||
Method(*int) *int // @implements I.Method "Method"
|
||||
}
|
|
@ -0,0 +1,283 @@
|
|||
-------- @implements F.f --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"name": "main.F",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:13:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
"to": [
|
||||
{
|
||||
"name": "*main.C",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:22:6",
|
||||
"kind": "pointer"
|
||||
},
|
||||
{
|
||||
"name": "main.D",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:23:6",
|
||||
"kind": "struct"
|
||||
},
|
||||
{
|
||||
"name": "main.FG",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:17:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (F).f()",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:14:2"
|
||||
},
|
||||
"to_method": [
|
||||
{
|
||||
"name": "method (*C) f()",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:25:13"
|
||||
},
|
||||
{
|
||||
"name": "method (D) f()",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:26:12"
|
||||
},
|
||||
{
|
||||
"name": "method (FG) f()",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:18:2"
|
||||
}
|
||||
]
|
||||
}
|
||||
}-------- @implements FG.f --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"name": "main.FG",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:17:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
"to": [
|
||||
{
|
||||
"name": "*main.D",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:23:6",
|
||||
"kind": "pointer"
|
||||
}
|
||||
],
|
||||
"from": [
|
||||
{
|
||||
"name": "main.F",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:13:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (FG).f()",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:18:2"
|
||||
},
|
||||
"to_method": [
|
||||
{
|
||||
"name": "method (*D) f()",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:26:12"
|
||||
}
|
||||
],
|
||||
"from_method": [
|
||||
{
|
||||
"name": "method (F) f()",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:14:2"
|
||||
}
|
||||
]
|
||||
}
|
||||
}-------- @implements FG.g --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"name": "main.FG",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:17:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
"to": [
|
||||
{
|
||||
"name": "*main.D",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:23:6",
|
||||
"kind": "pointer"
|
||||
}
|
||||
],
|
||||
"from": [
|
||||
{
|
||||
"name": "main.F",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:13:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (FG).g() []int",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:19:2"
|
||||
},
|
||||
"to_method": [
|
||||
{
|
||||
"name": "method (*D) g() []int",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:28:13"
|
||||
}
|
||||
],
|
||||
"from_method": [
|
||||
{
|
||||
"name": "",
|
||||
"pos": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}-------- @implements *C.f --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"name": "*main.C",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:22:6",
|
||||
"kind": "pointer"
|
||||
},
|
||||
"from": [
|
||||
{
|
||||
"name": "main.F",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:13:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (*C).f()",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:25:13"
|
||||
},
|
||||
"from_method": [
|
||||
{
|
||||
"name": "method (F) f()",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:14:2"
|
||||
}
|
||||
]
|
||||
}
|
||||
}-------- @implements D.f --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"name": "main.D",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:23:6",
|
||||
"kind": "struct"
|
||||
},
|
||||
"from": [
|
||||
{
|
||||
"name": "main.F",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:13:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"fromptr": [
|
||||
{
|
||||
"name": "main.FG",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:17:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (D).f()",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:26:12"
|
||||
},
|
||||
"from_method": [
|
||||
{
|
||||
"name": "method (F) f()",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:14:2"
|
||||
}
|
||||
],
|
||||
"fromptr_method": [
|
||||
{
|
||||
"name": "method (FG) f()",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:18:2"
|
||||
}
|
||||
]
|
||||
}
|
||||
}-------- @implements *D.g --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"name": "*main.D",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:23:6",
|
||||
"kind": "pointer"
|
||||
},
|
||||
"from": [
|
||||
{
|
||||
"name": "main.F",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:13:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
{
|
||||
"name": "main.FG",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:17:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (*D).g() []int",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:28:13"
|
||||
},
|
||||
"from_method": [
|
||||
{
|
||||
"name": "",
|
||||
"pos": ""
|
||||
},
|
||||
{
|
||||
"name": "method (FG) g() []int",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:19:2"
|
||||
}
|
||||
]
|
||||
}
|
||||
}-------- @implements Len --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"name": "main.sorter",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:30:6",
|
||||
"kind": "slice"
|
||||
},
|
||||
"from": [
|
||||
{
|
||||
"name": "sort.Interface",
|
||||
"pos": "/usr/local/google/home/adonovan/go/src/sort/sort.go:12:6",
|
||||
"kind": "interface"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (sorter).Len() int",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:32:15"
|
||||
},
|
||||
"from_method": [
|
||||
{
|
||||
"name": "method (sort.Interface) Len() int",
|
||||
"pos": "/usr/local/google/home/adonovan/go/src/sort/sort.go:14:2"
|
||||
}
|
||||
]
|
||||
}
|
||||
}-------- @implements I.Method --------
|
||||
{
|
||||
"mode": "implements",
|
||||
"implements": {
|
||||
"type": {
|
||||
"name": "main.I",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:36:6",
|
||||
"kind": "interface"
|
||||
},
|
||||
"to": [
|
||||
{
|
||||
"name": "lib.Type",
|
||||
"pos": "testdata/src/lib/lib.go:3:6",
|
||||
"kind": "basic"
|
||||
}
|
||||
],
|
||||
"method": {
|
||||
"name": "func (I).Method(*int) *int",
|
||||
"pos": "testdata/src/main/implements-methods-json.go:37:2"
|
||||
},
|
||||
"to_method": [
|
||||
{
|
||||
"name": "method (lib.Type) Method(x *int) *int",
|
||||
"pos": "testdata/src/lib/lib.go:5:13"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package main
|
||||
|
||||
// Tests of 'implements' query applied to methods.
|
||||
// See go.tools/oracle/oracle_test.go for explanation.
|
||||
// See implements-methods.golden for expected query results.
|
||||
|
||||
import _ "lib"
|
||||
import _ "sort"
|
||||
|
||||
func main() {
|
||||
}
|
||||
|
||||
type F interface {
|
||||
f() // @implements F.f "f"
|
||||
}
|
||||
|
||||
type FG interface {
|
||||
f() // @implements FG.f "f"
|
||||
g() []int // @implements FG.g "g"
|
||||
}
|
||||
|
||||
type C int
|
||||
type D struct{}
|
||||
|
||||
func (c *C) f() {} // @implements *C.f "f"
|
||||
func (d D) f() {} // @implements D.f "f"
|
||||
|
||||
func (d *D) g() []int { return nil } // @implements *D.g "g"
|
||||
|
||||
type sorter []int
|
||||
|
||||
func (sorter) Len() int { return 0 } // @implements Len "Len"
|
||||
func (sorter) Less(i, j int) bool { return false }
|
||||
func (sorter) Swap(i, j int) {}
|
||||
|
||||
type I interface {
|
||||
Method(*int) *int // @implements I.Method "Method"
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
-------- @implements F.f --------
|
||||
abstract method func (F).f()
|
||||
is implemented by method (*C).f
|
||||
is implemented by method (D).f
|
||||
is implemented by method (FG).f
|
||||
|
||||
-------- @implements FG.f --------
|
||||
abstract method func (FG).f()
|
||||
is implemented by method (*D).f
|
||||
implements method (F).f
|
||||
|
||||
-------- @implements FG.g --------
|
||||
abstract method func (FG).g() []int
|
||||
is implemented by method (*D).g
|
||||
|
||||
-------- @implements *C.f --------
|
||||
concrete method func (*C).f()
|
||||
implements method (F).f
|
||||
|
||||
-------- @implements D.f --------
|
||||
concrete method func (D).f()
|
||||
implements method (F).f
|
||||
concrete method func (D).f()
|
||||
implements method (FG).f
|
||||
|
||||
-------- @implements *D.g --------
|
||||
concrete method func (*D).g() []int
|
||||
implements method (FG).g
|
||||
|
||||
-------- @implements Len --------
|
||||
concrete method func (sorter).Len() int
|
||||
implements method (sort.Interface).Len
|
||||
|
||||
-------- @implements I.Method --------
|
||||
abstract method func (I).Method(*int) *int
|
||||
is implemented by method (lib.Type).Method
|
||||
|
Loading…
Reference in New Issue