1
0
mirror of https://github.com/golang/go synced 2024-11-18 09:04:49 -07:00

cmd/guru: describe: show methods and fields of an expression

Previously you had to describe a type to get this information,
which required two queries, and the need for this query is
extremely common.

Change-Id: I1d1d5b45fead60ca8719ddc302eee47d9f10a375
Reviewed-on: https://go-review.googlesource.com/19501
Reviewed-by: Michael Matloob <matloob@golang.org>
This commit is contained in:
Alan Donovan 2016-02-14 17:56:23 -05:00 committed by Alan Donovan
parent 608d57b3ae
commit 93ea01aea0
3 changed files with 82 additions and 36 deletions

View File

@ -14,6 +14,7 @@ import (
"log"
"os"
"strings"
"unicode/utf8"
"golang.org/x/tools/cmd/guru/serial"
"golang.org/x/tools/go/ast/astutil"
@ -325,15 +326,17 @@ func describeValue(qpos *queryPos, path []ast.Node) (*describeValueResult, error
return nil, fmt.Errorf("unexpected AST for expr: %T", n)
}
typ := qpos.info.TypeOf(expr)
t := qpos.info.TypeOf(expr)
constVal := qpos.info.Types[expr].Value
return &describeValueResult{
qpos: qpos,
expr: expr,
typ: typ,
typ: t,
constVal: constVal,
obj: obj,
methods: accessibleMethods(t, qpos.info.Pkg),
fields: accessibleFields(t, qpos.info.Pkg),
}, nil
}
@ -343,6 +346,8 @@ type describeValueResult struct {
typ types.Type // type of expression
constVal exact.Value // value of expression, if constant
obj types.Object // var/func/const object, if expr was Ident
methods []*types.Selection
fields []describeField
}
func (r *describeValueResult) display(printf printfFunc) {
@ -383,6 +388,9 @@ func (r *describeValueResult) display(printf printfFunc) {
printf(r.expr, "%s of type %s", desc, r.qpos.typeString(r.typ))
}
}
printMethods(printf, r.expr, r.methods)
printFields(printf, r.expr, r.fields)
}
func (r *describeValueResult) toSerial(res *serial.Result, fset *token.FileSet) {
@ -469,6 +477,48 @@ type describeField struct {
field *types.Var
}
func printMethods(printf printfFunc, node ast.Node, methods []*types.Selection) {
if len(methods) > 0 {
printf(node, "Method set:")
}
for _, meth := range methods {
// Print the method type relative to the package
// in which it was defined, not the query package,
printf(meth.Obj(), "\t%s",
types.SelectionString(meth, types.RelativeTo(meth.Obj().Pkg())))
}
}
func printFields(printf printfFunc, node ast.Node, fields []describeField) {
if len(fields) > 0 {
printf(node, "Fields:")
}
// Align the names and the types (requires two passes).
var width int
var names []string
for _, f := range fields {
var buf bytes.Buffer
for _, fld := range f.implicits {
buf.WriteString(fld.Obj().Name())
buf.WriteByte('.')
}
buf.WriteString(f.field.Name())
name := buf.String()
if n := utf8.RuneCountInString(name); n > width {
width = n
}
names = append(names, name)
}
for i, f := range fields {
// Print the field type relative to the package
// in which it was defined, not the query package,
printf(f.field, "\t%*s %s", -width, names[i],
types.TypeString(f.field.Type(), types.RelativeTo(f.field.Pkg())))
}
}
func (r *describeTypeResult) display(printf printfFunc) {
printf(r.node, "%s", r.description)
@ -477,38 +527,17 @@ func (r *describeTypeResult) display(printf printfFunc) {
printf(nt.Obj(), "defined as %s", r.qpos.typeString(nt.Underlying()))
}
// Print the method set, if the type kind is capable of bearing methods.
switch r.typ.(type) {
case *types.Interface, *types.Struct, *types.Named:
if len(r.methods) > 0 {
printf(r.node, "Method set:")
for _, meth := range r.methods {
// Print the method type relative to the package
// in which it was defined, not the query package,
printf(meth.Obj(), "\t%s",
types.SelectionString(meth, types.RelativeTo(meth.Obj().Pkg())))
}
} else {
printMethods(printf, r.node, r.methods)
if len(r.methods) == 0 {
// Only report null result for type kinds
// capable of bearing methods.
switch r.typ.(type) {
case *types.Interface, *types.Struct, *types.Named:
printf(r.node, "No methods.")
}
}
// Print the fields, if any.
if len(r.fields) > 0 {
printf(r.node, "Fields:")
for _, f := range r.fields {
var buf bytes.Buffer
for _, fld := range f.implicits {
buf.WriteString(fld.Obj().Name())
buf.WriteByte('.')
}
// Print the field type relative to the package
// in which it was defined, not the query package,
printf(f.field, "\t%s%s %s", buf.String(), f.field.Name(),
types.TypeString(f.field.Type(), types.RelativeTo(f.field.Pkg())))
}
}
printFields(printf, r.node, r.fields)
}
func (r *describeTypeResult) toSerial(res *serial.Result, fset *token.FileSet) {

View File

@ -93,7 +93,10 @@ type I interface { // @describe def-iface-I "I"
}
type C int
type D struct{}
type D struct {
Field int
AnotherField string
}
func (c *C) f() {}
func (d D) f() {}

View File

@ -2,7 +2,7 @@
definition of package "describe"
type C int
method (*C) f()
type D struct{}
type D struct{...}
method (D) f()
type I interface{f()}
method (I) f()
@ -62,10 +62,13 @@ reference to interface method func (I).f()
defined here
-------- @describe type-D --------
reference to type D (size 0, align 1)
defined as struct{}
reference to type D (size 24, align 8)
defined as struct{Field int; AnotherField string}
Method set:
method (D) f()
Fields:
Field int
AnotherField string
-------- @describe type-I --------
reference to type I (size 16, align 8)
@ -84,6 +87,11 @@ defined here
-------- @describe ref-lexical-d --------
reference to var d D
defined here
Method set:
method (D) f()
Fields:
Field int
AnotherField string
-------- @describe ref-anon --------
reference to var anon func()
@ -111,14 +119,20 @@ defined here
-------- @describe var-ref-i-C --------
reference to var i I
defined here
Method set:
method (I) f()
-------- @describe var-ref-i-D --------
reference to var i I
defined here
Method set:
method (I) f()
-------- @describe var-ref-i --------
reference to var i I
defined here
Method set:
method (I) f()
-------- @describe const-local-pi --------
definition of const localpi untyped float
@ -179,8 +193,8 @@ reference to type lib.Outer (size 56, align 8)
defined as struct{A int; b int; lib.inner}
No methods.
Fields:
A int
inner.C bool
A int
inner.C bool
inner.recursive.E bool
-------- @describe def-iface-I --------