Skip to content

Commit

Permalink
cmd/guru: add type position to describe command
Browse files Browse the repository at this point in the history
Add typepos field to json output of describe command. This field shows where
type of current (under cursor) identifier is defined. This will help code editors
implement command 'Go to type definition'.

Implements [#27308](golang/go#27308)

Change-Id: I4e02ddbdc03fecec98135b8996f9562a88a9cfb8
GitHub-Last-Rev: be47e39
GitHub-Pull-Request: #50
Reviewed-on: https://go-review.googlesource.com/c/140379
Reviewed-by: Alan Donovan <[email protected]>
  • Loading branch information
Dima authored and adonovan committed Nov 20, 2018
1 parent b6bf295 commit 9c8bd46
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 20 deletions.
54 changes: 51 additions & 3 deletions cmd/guru/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,17 +340,42 @@ func describeValue(qpos *queryPos, path []ast.Node) (*describeValueResult, error
qpos: qpos,
expr: expr,
typ: typ,
names: appendNames(nil, typ),
constVal: constVal,
obj: obj,
methods: accessibleMethods(typ, qpos.info.Pkg),
fields: accessibleFields(typ, qpos.info.Pkg),
}, nil
}

// appendNames returns named types found within the Type by
// removing map, pointer, channel, slice, and array constructors.
// It does not descend into structs or interfaces.
func appendNames(names []*types.Named, typ types.Type) []*types.Named {
// elemType specifies type that has some element in it
// such as array, slice, chan, pointer
type elemType interface {
Elem() types.Type
}

switch t := typ.(type) {
case *types.Named:
names = append(names, t)
case *types.Map:
names = appendNames(names, t.Key())
names = appendNames(names, t.Elem())
case elemType:
names = appendNames(names, t.Elem())
}

return names
}

type describeValueResult struct {
qpos *queryPos
expr ast.Expr // query node
typ types.Type // type of expression
names []*types.Named // named types within typ
constVal constant.Value // value of expression, if constant
obj types.Object // var/func/const object, if expr was Ident
methods []*types.Selection
Expand Down Expand Up @@ -398,6 +423,7 @@ func (r *describeValueResult) PrintPlain(printf printfFunc) {

printMethods(printf, r.expr, r.methods)
printFields(printf, r.expr, r.fields)
printNamedTypes(printf, r.expr, r.names)
}

func (r *describeValueResult) JSON(fset *token.FileSet) []byte {
Expand All @@ -409,14 +435,23 @@ func (r *describeValueResult) JSON(fset *token.FileSet) []byte {
objpos = fset.Position(r.obj.Pos()).String()
}

typesPos := make([]serial.Definition, len(r.names))
for i, t := range r.names {
typesPos[i] = serial.Definition{
ObjPos: fset.Position(t.Obj().Pos()).String(),
Desc: r.qpos.typeString(t),
}
}

return toJSON(&serial.Describe{
Desc: astutil.NodeDescription(r.expr),
Pos: fset.Position(r.expr.Pos()).String(),
Detail: "value",
Value: &serial.DescribeValue{
Type: r.qpos.typeString(r.typ),
Value: value,
ObjPos: objpos,
Type: r.qpos.typeString(r.typ),
TypesPos: typesPos,
Value: value,
ObjPos: objpos,
},
})
}
Expand Down Expand Up @@ -524,6 +559,19 @@ func printFields(printf printfFunc, node ast.Node, fields []describeField) {
}
}

func printNamedTypes(printf printfFunc, node ast.Node, names []*types.Named) {
if len(names) > 0 {
printf(node, "Named types:")
}

for _, t := range names {
// Print the type relative to the package
// in which it was defined, not the query package,
printf(t.Obj(), "\ttype %s defined here",
types.TypeString(t.Obj().Type(), types.RelativeTo(t.Obj().Pkg())))
}
}

func (r *describeTypeResult) PrintPlain(printf printfFunc) {
printf(r.node, "%s", r.description)

Expand Down
7 changes: 4 additions & 3 deletions cmd/guru/serial/serial.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,10 @@ type PointsTo struct {
// A DescribeValue is the additional result of a 'describe' query
// if the selection indicates a value or expression.
type DescribeValue struct {
Type string `json:"type"` // type of the expression
Value string `json:"value,omitempty"` // value of the expression, if constant
ObjPos string `json:"objpos,omitempty"` // location of the definition, if an Ident
Type string `json:"type"` // type of the expression
Value string `json:"value,omitempty"` // value of the expression, if constant
ObjPos string `json:"objpos,omitempty"` // location of the definition, if an Ident
TypesPos []Definition `json:"typespos,omitempty"` // location of the named types, that type consist of
}

type DescribeMethod struct {
Expand Down
4 changes: 2 additions & 2 deletions cmd/guru/testdata/src/describe-json/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ type I interface {
type C int // @describe desc-type-C "C"
type D struct{}

func (c C) f() {}
func (d *D) f() {}
func (c C) f() {} // @describe desc-param-c "\\bc\\b"
func (d *D) f() {} // @describe desc-param-d "\\bd\\b"
40 changes: 39 additions & 1 deletion cmd/guru/testdata/src/describe-json/main.golden
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,13 @@
"detail": "value",
"value": {
"type": "I",
"objpos": "testdata/src/describe-json/main.go:12:6"
"objpos": "testdata/src/describe-json/main.go:12:6",
"typespos": [
{
"objpos": "testdata/src/describe-json/main.go:21:6",
"desc": "I"
}
]
}
}
-------- @describe desc-stmt --------
Expand All @@ -94,3 +100,35 @@
]
}
}
-------- @describe desc-param-c --------
{
"desc": "identifier",
"pos": "testdata/src/describe-json/main.go:28:7",
"detail": "value",
"value": {
"type": "C",
"objpos": "testdata/src/describe-json/main.go:28:7",
"typespos": [
{
"objpos": "testdata/src/describe-json/main.go:25:6",
"desc": "C"
}
]
}
}
-------- @describe desc-param-d --------
{
"desc": "identifier",
"pos": "testdata/src/describe-json/main.go:29:7",
"detail": "value",
"value": {
"type": "*D",
"objpos": "testdata/src/describe-json/main.go:29:7",
"typespos": [
{
"objpos": "testdata/src/describe-json/main.go:26:6",
"desc": "D"
}
]
}
}
25 changes: 17 additions & 8 deletions cmd/guru/testdata/src/describe/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ var global = new(string) // NB: ssa.Global is indirect, i.e. **string

func main() { // @describe func-def-main "main"
// func objects
_ = main // @describe func-ref-main "main"
_ = (*C).f // @describe func-ref-*C.f "..C..f"
_ = D.f // @describe func-ref-D.f "D.f"
_ = I.f // @describe func-ref-I.f "I.f"
var d D // @describe type-D "D"
var i I // @describe type-I "I"
_ = d.f // @describe func-ref-d.f "d.f"
_ = i.f // @describe func-ref-i.f "i.f"
_ = main // @describe func-ref-main "main"
_ = (*C).f // @describe func-ref-*C.f "..C..f"
_ = D.f // @describe func-ref-D.f "D.f"
_ = I.f // @describe func-ref-I.f "I.f"
var d D // @describe type-D "D"
var i I // @describe type-I "I"
_ = d.f // @describe func-ref-d.f "d.f"
_ = i.f // @describe func-ref-i.f "i.f"
var slice []D // @describe slice-of-D "slice"

var dptr *D // @describe ptr-with-nonptr-methods "dptr"
_ = dptr
Expand Down Expand Up @@ -85,6 +86,11 @@ func main() { // @describe func-def-main "main"

var _ lib.Outer // @describe lib-outer "Outer"

var mmm map[C]D // @describe var-map-of-C-D "mmm"

d := newD().ThirdField // @describe field-access "ThirdField"

astCopy := ast
unknown() // @describe call-unknown "\\("
}

Expand All @@ -96,7 +102,10 @@ type C int
type D struct {
Field int
AnotherField string
ThirdField C
}

func (c *C) f() {}
func (d D) f() {}

func newD() D { return D{} }
41 changes: 39 additions & 2 deletions cmd/guru/testdata/src/describe/main.golden
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ definition of package "describe"
type cake float64
var global *string
func main func()
func newD func() D
const pi untyped float = 3.141
const pie cake = 3.141

Expand All @@ -31,6 +32,8 @@ definition of const pi untyped float of value 3.141

-------- @describe const-def-pie --------
definition of const pie cake of value 3.141
Named types:
type cake defined here

-------- @describe const-ref-pi --------
reference to const pi untyped float of value 3.141
Expand All @@ -56,13 +59,14 @@ reference to interface method func (I).f()
defined here

-------- @describe type-D --------
reference to type D (size 24, align 8)
defined as struct{Field int; AnotherField string}
reference to type D (size 32, align 8)
defined as struct{Field int; AnotherField string; ThirdField C}
Methods:
method (D) f()
Fields:
Field int
AnotherField string
ThirdField C

-------- @describe type-I --------
reference to type I (size 16, align 8)
Expand All @@ -78,13 +82,21 @@ defined here
reference to interface method func (I).f()
defined here

-------- @describe slice-of-D --------
definition of var slice []D
Named types:
type D defined here

-------- @describe ptr-with-nonptr-methods --------
definition of var dptr *D
Methods:
method (*D) f()
Fields:
Field int
AnotherField string
ThirdField C
Named types:
type D defined here

-------- @describe ref-lexical-d --------
reference to var d D
Expand All @@ -94,6 +106,9 @@ Methods:
Fields:
Field int
AnotherField string
ThirdField C
Named types:
type D defined here

-------- @describe ref-anon --------
reference to var anon func()
Expand Down Expand Up @@ -123,24 +138,32 @@ reference to var i I
defined here
Methods:
method (I) f()
Named types:
type I defined here

-------- @describe var-ref-i-D --------
reference to var i I
defined here
Methods:
method (I) f()
Named types:
type I defined here

-------- @describe var-ref-i --------
reference to var i I
defined here
Methods:
method (I) f()
Named types:
type I defined here

-------- @describe const-local-pi --------
definition of const localpi untyped float of value 3.141

-------- @describe const-local-pie --------
definition of const localpie cake of value 3.141
Named types:
type cake defined here

-------- @describe const-ref-localpi --------
reference to const localpi untyped float of value 3.141
Expand Down Expand Up @@ -199,6 +222,20 @@ Fields:
inner.C bool
inner.recursive.E bool

-------- @describe var-map-of-C-D --------
definition of var mmm map[C]D
Named types:
type C defined here
type D defined here

-------- @describe field-access --------
reference to field ThirdField C
defined here
Methods:
method (*C) f()
Named types:
type C defined here

-------- @describe call-unknown --------
function call of type invalid type

Expand Down
2 changes: 1 addition & 1 deletion cmd/guru/testdata/src/referrers-json/main.golden
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"package": "describe",
"refs": [
{
"pos": "testdata/src/describe/main.go:86:8",
"pos": "testdata/src/describe/main.go:87:8",
"text": "\tvar _ lib.Outer // @describe lib-outer \"Outer\""
}
]
Expand Down

0 comments on commit 9c8bd46

Please sign in to comment.