Skip to content

Commit 9c8bd46

Browse files
Dimaadonovan
Dima
authored andcommitted
cmd/guru: add type position to describe command
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 <adonovan@google.com>
1 parent b6bf295 commit 9c8bd46

File tree

7 files changed

+153
-20
lines changed

7 files changed

+153
-20
lines changed

cmd/guru/describe.go

+51-3
Original file line numberDiff line numberDiff line change
@@ -340,17 +340,42 @@ func describeValue(qpos *queryPos, path []ast.Node) (*describeValueResult, error
340340
qpos: qpos,
341341
expr: expr,
342342
typ: typ,
343+
names: appendNames(nil, typ),
343344
constVal: constVal,
344345
obj: obj,
345346
methods: accessibleMethods(typ, qpos.info.Pkg),
346347
fields: accessibleFields(typ, qpos.info.Pkg),
347348
}, nil
348349
}
349350

351+
// appendNames returns named types found within the Type by
352+
// removing map, pointer, channel, slice, and array constructors.
353+
// It does not descend into structs or interfaces.
354+
func appendNames(names []*types.Named, typ types.Type) []*types.Named {
355+
// elemType specifies type that has some element in it
356+
// such as array, slice, chan, pointer
357+
type elemType interface {
358+
Elem() types.Type
359+
}
360+
361+
switch t := typ.(type) {
362+
case *types.Named:
363+
names = append(names, t)
364+
case *types.Map:
365+
names = appendNames(names, t.Key())
366+
names = appendNames(names, t.Elem())
367+
case elemType:
368+
names = appendNames(names, t.Elem())
369+
}
370+
371+
return names
372+
}
373+
350374
type describeValueResult struct {
351375
qpos *queryPos
352376
expr ast.Expr // query node
353377
typ types.Type // type of expression
378+
names []*types.Named // named types within typ
354379
constVal constant.Value // value of expression, if constant
355380
obj types.Object // var/func/const object, if expr was Ident
356381
methods []*types.Selection
@@ -398,6 +423,7 @@ func (r *describeValueResult) PrintPlain(printf printfFunc) {
398423

399424
printMethods(printf, r.expr, r.methods)
400425
printFields(printf, r.expr, r.fields)
426+
printNamedTypes(printf, r.expr, r.names)
401427
}
402428

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

438+
typesPos := make([]serial.Definition, len(r.names))
439+
for i, t := range r.names {
440+
typesPos[i] = serial.Definition{
441+
ObjPos: fset.Position(t.Obj().Pos()).String(),
442+
Desc: r.qpos.typeString(t),
443+
}
444+
}
445+
412446
return toJSON(&serial.Describe{
413447
Desc: astutil.NodeDescription(r.expr),
414448
Pos: fset.Position(r.expr.Pos()).String(),
415449
Detail: "value",
416450
Value: &serial.DescribeValue{
417-
Type: r.qpos.typeString(r.typ),
418-
Value: value,
419-
ObjPos: objpos,
451+
Type: r.qpos.typeString(r.typ),
452+
TypesPos: typesPos,
453+
Value: value,
454+
ObjPos: objpos,
420455
},
421456
})
422457
}
@@ -524,6 +559,19 @@ func printFields(printf printfFunc, node ast.Node, fields []describeField) {
524559
}
525560
}
526561

562+
func printNamedTypes(printf printfFunc, node ast.Node, names []*types.Named) {
563+
if len(names) > 0 {
564+
printf(node, "Named types:")
565+
}
566+
567+
for _, t := range names {
568+
// Print the type relative to the package
569+
// in which it was defined, not the query package,
570+
printf(t.Obj(), "\ttype %s defined here",
571+
types.TypeString(t.Obj().Type(), types.RelativeTo(t.Obj().Pkg())))
572+
}
573+
}
574+
527575
func (r *describeTypeResult) PrintPlain(printf printfFunc) {
528576
printf(r.node, "%s", r.description)
529577

cmd/guru/serial/serial.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,10 @@ type PointsTo struct {
193193
// A DescribeValue is the additional result of a 'describe' query
194194
// if the selection indicates a value or expression.
195195
type DescribeValue struct {
196-
Type string `json:"type"` // type of the expression
197-
Value string `json:"value,omitempty"` // value of the expression, if constant
198-
ObjPos string `json:"objpos,omitempty"` // location of the definition, if an Ident
196+
Type string `json:"type"` // type of the expression
197+
Value string `json:"value,omitempty"` // value of the expression, if constant
198+
ObjPos string `json:"objpos,omitempty"` // location of the definition, if an Ident
199+
TypesPos []Definition `json:"typespos,omitempty"` // location of the named types, that type consist of
199200
}
200201

201202
type DescribeMethod struct {

cmd/guru/testdata/src/describe-json/main.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@ type I interface {
2525
type C int // @describe desc-type-C "C"
2626
type D struct{}
2727

28-
func (c C) f() {}
29-
func (d *D) f() {}
28+
func (c C) f() {} // @describe desc-param-c "\\bc\\b"
29+
func (d *D) f() {} // @describe desc-param-d "\\bd\\b"

cmd/guru/testdata/src/describe-json/main.golden

+39-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,13 @@
6868
"detail": "value",
6969
"value": {
7070
"type": "I",
71-
"objpos": "testdata/src/describe-json/main.go:12:6"
71+
"objpos": "testdata/src/describe-json/main.go:12:6",
72+
"typespos": [
73+
{
74+
"objpos": "testdata/src/describe-json/main.go:21:6",
75+
"desc": "I"
76+
}
77+
]
7278
}
7379
}
7480
-------- @describe desc-stmt --------
@@ -94,3 +100,35 @@
94100
]
95101
}
96102
}
103+
-------- @describe desc-param-c --------
104+
{
105+
"desc": "identifier",
106+
"pos": "testdata/src/describe-json/main.go:28:7",
107+
"detail": "value",
108+
"value": {
109+
"type": "C",
110+
"objpos": "testdata/src/describe-json/main.go:28:7",
111+
"typespos": [
112+
{
113+
"objpos": "testdata/src/describe-json/main.go:25:6",
114+
"desc": "C"
115+
}
116+
]
117+
}
118+
}
119+
-------- @describe desc-param-d --------
120+
{
121+
"desc": "identifier",
122+
"pos": "testdata/src/describe-json/main.go:29:7",
123+
"detail": "value",
124+
"value": {
125+
"type": "*D",
126+
"objpos": "testdata/src/describe-json/main.go:29:7",
127+
"typespos": [
128+
{
129+
"objpos": "testdata/src/describe-json/main.go:26:6",
130+
"desc": "D"
131+
}
132+
]
133+
}
134+
}

cmd/guru/testdata/src/describe/main.go

+17-8
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,15 @@ var global = new(string) // NB: ssa.Global is indirect, i.e. **string
2323

2424
func main() { // @describe func-def-main "main"
2525
// func objects
26-
_ = main // @describe func-ref-main "main"
27-
_ = (*C).f // @describe func-ref-*C.f "..C..f"
28-
_ = D.f // @describe func-ref-D.f "D.f"
29-
_ = I.f // @describe func-ref-I.f "I.f"
30-
var d D // @describe type-D "D"
31-
var i I // @describe type-I "I"
32-
_ = d.f // @describe func-ref-d.f "d.f"
33-
_ = i.f // @describe func-ref-i.f "i.f"
26+
_ = main // @describe func-ref-main "main"
27+
_ = (*C).f // @describe func-ref-*C.f "..C..f"
28+
_ = D.f // @describe func-ref-D.f "D.f"
29+
_ = I.f // @describe func-ref-I.f "I.f"
30+
var d D // @describe type-D "D"
31+
var i I // @describe type-I "I"
32+
_ = d.f // @describe func-ref-d.f "d.f"
33+
_ = i.f // @describe func-ref-i.f "i.f"
34+
var slice []D // @describe slice-of-D "slice"
3435

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

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

89+
var mmm map[C]D // @describe var-map-of-C-D "mmm"
90+
91+
d := newD().ThirdField // @describe field-access "ThirdField"
92+
93+
astCopy := ast
8894
unknown() // @describe call-unknown "\\("
8995
}
9096

@@ -96,7 +102,10 @@ type C int
96102
type D struct {
97103
Field int
98104
AnotherField string
105+
ThirdField C
99106
}
100107

101108
func (c *C) f() {}
102109
func (d D) f() {}
110+
111+
func newD() D { return D{} }

cmd/guru/testdata/src/describe/main.golden

+39-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ definition of package "describe"
1010
type cake float64
1111
var global *string
1212
func main func()
13+
func newD func() D
1314
const pi untyped float = 3.141
1415
const pie cake = 3.141
1516

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

3233
-------- @describe const-def-pie --------
3334
definition of const pie cake of value 3.141
35+
Named types:
36+
type cake defined here
3437

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

5861
-------- @describe type-D --------
59-
reference to type D (size 24, align 8)
60-
defined as struct{Field int; AnotherField string}
62+
reference to type D (size 32, align 8)
63+
defined as struct{Field int; AnotherField string; ThirdField C}
6164
Methods:
6265
method (D) f()
6366
Fields:
6467
Field int
6568
AnotherField string
69+
ThirdField C
6670

6771
-------- @describe type-I --------
6872
reference to type I (size 16, align 8)
@@ -78,13 +82,21 @@ defined here
7882
reference to interface method func (I).f()
7983
defined here
8084

85+
-------- @describe slice-of-D --------
86+
definition of var slice []D
87+
Named types:
88+
type D defined here
89+
8190
-------- @describe ptr-with-nonptr-methods --------
8291
definition of var dptr *D
8392
Methods:
8493
method (*D) f()
8594
Fields:
8695
Field int
8796
AnotherField string
97+
ThirdField C
98+
Named types:
99+
type D defined here
88100

89101
-------- @describe ref-lexical-d --------
90102
reference to var d D
@@ -94,6 +106,9 @@ Methods:
94106
Fields:
95107
Field int
96108
AnotherField string
109+
ThirdField C
110+
Named types:
111+
type D defined here
97112

98113
-------- @describe ref-anon --------
99114
reference to var anon func()
@@ -123,24 +138,32 @@ reference to var i I
123138
defined here
124139
Methods:
125140
method (I) f()
141+
Named types:
142+
type I defined here
126143

127144
-------- @describe var-ref-i-D --------
128145
reference to var i I
129146
defined here
130147
Methods:
131148
method (I) f()
149+
Named types:
150+
type I defined here
132151

133152
-------- @describe var-ref-i --------
134153
reference to var i I
135154
defined here
136155
Methods:
137156
method (I) f()
157+
Named types:
158+
type I defined here
138159

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

142163
-------- @describe const-local-pie --------
143164
definition of const localpie cake of value 3.141
165+
Named types:
166+
type cake defined here
144167

145168
-------- @describe const-ref-localpi --------
146169
reference to const localpi untyped float of value 3.141
@@ -199,6 +222,20 @@ Fields:
199222
inner.C bool
200223
inner.recursive.E bool
201224

225+
-------- @describe var-map-of-C-D --------
226+
definition of var mmm map[C]D
227+
Named types:
228+
type C defined here
229+
type D defined here
230+
231+
-------- @describe field-access --------
232+
reference to field ThirdField C
233+
defined here
234+
Methods:
235+
method (*C) f()
236+
Named types:
237+
type C defined here
238+
202239
-------- @describe call-unknown --------
203240
function call of type invalid type
204241

cmd/guru/testdata/src/referrers-json/main.golden

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"package": "describe",
4444
"refs": [
4545
{
46-
"pos": "testdata/src/describe/main.go:86:8",
46+
"pos": "testdata/src/describe/main.go:87:8",
4747
"text": "\tvar _ lib.Outer // @describe lib-outer \"Outer\""
4848
}
4949
]

0 commit comments

Comments
 (0)