Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / cmd / guru / describe.go
1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package main
6
7 import (
8         "bytes"
9         "fmt"
10         "go/ast"
11         "go/constant"
12         "go/token"
13         "go/types"
14         "os"
15         "strings"
16         "unicode/utf8"
17
18         "golang.org/x/tools/cmd/guru/serial"
19         "golang.org/x/tools/go/ast/astutil"
20         "golang.org/x/tools/go/loader"
21         "golang.org/x/tools/go/types/typeutil"
22 )
23
24 // describe describes the syntax node denoted by the query position,
25 // including:
26 // - its syntactic category
27 // - the definition of its referent (for identifiers) [now redundant]
28 // - its type, fields, and methods (for an expression or type expression)
29 //
30 func describe(q *Query) error {
31         lconf := loader.Config{Build: q.Build}
32         allowErrors(&lconf)
33
34         if _, err := importQueryPackage(q.Pos, &lconf); err != nil {
35                 return err
36         }
37
38         // Load/parse/type-check the program.
39         lprog, err := lconf.Load()
40         if err != nil {
41                 return err
42         }
43
44         qpos, err := parseQueryPos(lprog, q.Pos, true) // (need exact pos)
45         if err != nil {
46                 return err
47         }
48
49         if false { // debugging
50                 fprintf(os.Stderr, lprog.Fset, qpos.path[0], "you selected: %s %s",
51                         astutil.NodeDescription(qpos.path[0]), pathToString(qpos.path))
52         }
53
54         var qr QueryResult
55         path, action := findInterestingNode(qpos.info, qpos.path)
56         switch action {
57         case actionExpr:
58                 qr, err = describeValue(qpos, path)
59
60         case actionType:
61                 qr, err = describeType(qpos, path)
62
63         case actionPackage:
64                 qr, err = describePackage(qpos, path)
65
66         case actionStmt:
67                 qr, err = describeStmt(qpos, path)
68
69         case actionUnknown:
70                 qr = &describeUnknownResult{path[0]}
71
72         default:
73                 panic(action) // unreachable
74         }
75         if err != nil {
76                 return err
77         }
78         q.Output(lprog.Fset, qr)
79         return nil
80 }
81
82 type describeUnknownResult struct {
83         node ast.Node
84 }
85
86 func (r *describeUnknownResult) PrintPlain(printf printfFunc) {
87         // Nothing much to say about misc syntax.
88         printf(r.node, "%s", astutil.NodeDescription(r.node))
89 }
90
91 func (r *describeUnknownResult) JSON(fset *token.FileSet) []byte {
92         return toJSON(&serial.Describe{
93                 Desc: astutil.NodeDescription(r.node),
94                 Pos:  fset.Position(r.node.Pos()).String(),
95         })
96 }
97
98 type action int
99
100 const (
101         actionUnknown action = iota // None of the below
102         actionExpr                  // FuncDecl, true Expr or Ident(types.{Const,Var})
103         actionType                  // type Expr or Ident(types.TypeName).
104         actionStmt                  // Stmt or Ident(types.Label)
105         actionPackage               // Ident(types.Package) or ImportSpec
106 )
107
108 // findInterestingNode classifies the syntax node denoted by path as one of:
109 //    - an expression, part of an expression or a reference to a constant
110 //      or variable;
111 //    - a type, part of a type, or a reference to a named type;
112 //    - a statement, part of a statement, or a label referring to a statement;
113 //    - part of a package declaration or import spec.
114 //    - none of the above.
115 // and returns the most "interesting" associated node, which may be
116 // the same node, an ancestor or a descendent.
117 //
118 func findInterestingNode(pkginfo *loader.PackageInfo, path []ast.Node) ([]ast.Node, action) {
119         // TODO(adonovan): integrate with go/types/stdlib_test.go and
120         // apply this to every AST node we can find to make sure it
121         // doesn't crash.
122
123         // TODO(adonovan): audit for ParenExpr safety, esp. since we
124         // traverse up and down.
125
126         // TODO(adonovan): if the users selects the "." in
127         // "fmt.Fprintf()", they'll get an ambiguous selection error;
128         // we won't even reach here.  Can we do better?
129
130         // TODO(adonovan): describing a field within 'type T struct {...}'
131         // describes the (anonymous) struct type and concludes "no methods".
132         // We should ascend to the enclosing type decl, if any.
133
134         for len(path) > 0 {
135                 switch n := path[0].(type) {
136                 case *ast.GenDecl:
137                         if len(n.Specs) == 1 {
138                                 // Descend to sole {Import,Type,Value}Spec child.
139                                 path = append([]ast.Node{n.Specs[0]}, path...)
140                                 continue
141                         }
142                         return path, actionUnknown // uninteresting
143
144                 case *ast.FuncDecl:
145                         // Descend to function name.
146                         path = append([]ast.Node{n.Name}, path...)
147                         continue
148
149                 case *ast.ImportSpec:
150                         return path, actionPackage
151
152                 case *ast.ValueSpec:
153                         if len(n.Names) == 1 {
154                                 // Descend to sole Ident child.
155                                 path = append([]ast.Node{n.Names[0]}, path...)
156                                 continue
157                         }
158                         return path, actionUnknown // uninteresting
159
160                 case *ast.TypeSpec:
161                         // Descend to type name.
162                         path = append([]ast.Node{n.Name}, path...)
163                         continue
164
165                 case *ast.Comment, *ast.CommentGroup, *ast.File, *ast.KeyValueExpr, *ast.CommClause:
166                         return path, actionUnknown // uninteresting
167
168                 case ast.Stmt:
169                         return path, actionStmt
170
171                 case *ast.ArrayType,
172                         *ast.StructType,
173                         *ast.FuncType,
174                         *ast.InterfaceType,
175                         *ast.MapType,
176                         *ast.ChanType:
177                         return path, actionType
178
179                 case *ast.Ellipsis:
180                         // Continue to enclosing node.
181                         // e.g. [...]T in ArrayType
182                         //      f(x...) in CallExpr
183                         //      f(x...T) in FuncType
184
185                 case *ast.Field:
186                         // TODO(adonovan): this needs more thought,
187                         // since fields can be so many things.
188                         if len(n.Names) == 1 {
189                                 // Descend to sole Ident child.
190                                 path = append([]ast.Node{n.Names[0]}, path...)
191                                 continue
192                         }
193                         // Zero names (e.g. anon field in struct)
194                         // or multiple field or param names:
195                         // continue to enclosing field list.
196
197                 case *ast.FieldList:
198                         // Continue to enclosing node:
199                         // {Struct,Func,Interface}Type or FuncDecl.
200
201                 case *ast.BasicLit:
202                         if _, ok := path[1].(*ast.ImportSpec); ok {
203                                 return path[1:], actionPackage
204                         }
205                         return path, actionExpr
206
207                 case *ast.SelectorExpr:
208                         // TODO(adonovan): use Selections info directly.
209                         if pkginfo.Uses[n.Sel] == nil {
210                                 // TODO(adonovan): is this reachable?
211                                 return path, actionUnknown
212                         }
213                         // Descend to .Sel child.
214                         path = append([]ast.Node{n.Sel}, path...)
215                         continue
216
217                 case *ast.Ident:
218                         switch pkginfo.ObjectOf(n).(type) {
219                         case *types.PkgName:
220                                 return path, actionPackage
221
222                         case *types.Const:
223                                 return path, actionExpr
224
225                         case *types.Label:
226                                 return path, actionStmt
227
228                         case *types.TypeName:
229                                 return path, actionType
230
231                         case *types.Var:
232                                 // For x in 'struct {x T}', return struct type, for now.
233                                 if _, ok := path[1].(*ast.Field); ok {
234                                         _ = path[2].(*ast.FieldList) // assertion
235                                         if _, ok := path[3].(*ast.StructType); ok {
236                                                 return path[3:], actionType
237                                         }
238                                 }
239                                 return path, actionExpr
240
241                         case *types.Func:
242                                 return path, actionExpr
243
244                         case *types.Builtin:
245                                 // For reference to built-in function, return enclosing call.
246                                 path = path[1:] // ascend to enclosing function call
247                                 continue
248
249                         case *types.Nil:
250                                 return path, actionExpr
251                         }
252
253                         // No object.
254                         switch path[1].(type) {
255                         case *ast.SelectorExpr:
256                                 // Return enclosing selector expression.
257                                 return path[1:], actionExpr
258
259                         case *ast.Field:
260                                 // TODO(adonovan): test this.
261                                 // e.g. all f in:
262                                 //  struct { f, g int }
263                                 //  interface { f() }
264                                 //  func (f T) method(f, g int) (f, g bool)
265                                 //
266                                 // switch path[3].(type) {
267                                 // case *ast.FuncDecl:
268                                 // case *ast.StructType:
269                                 // case *ast.InterfaceType:
270                                 // }
271                                 //
272                                 // return path[1:], actionExpr
273                                 //
274                                 // Unclear what to do with these.
275                                 // Struct.Fields             -- field
276                                 // Interface.Methods         -- field
277                                 // FuncType.{Params.Results} -- actionExpr
278                                 // FuncDecl.Recv             -- actionExpr
279
280                         case *ast.File:
281                                 // 'package foo'
282                                 return path, actionPackage
283
284                         case *ast.ImportSpec:
285                                 return path[1:], actionPackage
286
287                         default:
288                                 // e.g. blank identifier
289                                 // or y in "switch y := x.(type)"
290                                 // or code in a _test.go file that's not part of the package.
291                                 return path, actionUnknown
292                         }
293
294                 case *ast.StarExpr:
295                         if pkginfo.Types[n].IsType() {
296                                 return path, actionType
297                         }
298                         return path, actionExpr
299
300                 case ast.Expr:
301                         // All Expr but {BasicLit,Ident,StarExpr} are
302                         // "true" expressions that evaluate to a value.
303                         return path, actionExpr
304                 }
305
306                 // Ascend to parent.
307                 path = path[1:]
308         }
309
310         return nil, actionUnknown // unreachable
311 }
312
313 func describeValue(qpos *queryPos, path []ast.Node) (*describeValueResult, error) {
314         var expr ast.Expr
315         var obj types.Object
316         switch n := path[0].(type) {
317         case *ast.ValueSpec:
318                 // ambiguous ValueSpec containing multiple names
319                 return nil, fmt.Errorf("multiple value specification")
320         case *ast.Ident:
321                 obj = qpos.info.ObjectOf(n)
322                 expr = n
323         case ast.Expr:
324                 expr = n
325         default:
326                 // TODO(adonovan): is this reachable?
327                 return nil, fmt.Errorf("unexpected AST for expr: %T", n)
328         }
329
330         typ := qpos.info.TypeOf(expr)
331         if typ == nil {
332                 typ = types.Typ[types.Invalid]
333         }
334         constVal := qpos.info.Types[expr].Value
335         if c, ok := obj.(*types.Const); ok {
336                 constVal = c.Val()
337         }
338
339         return &describeValueResult{
340                 qpos:     qpos,
341                 expr:     expr,
342                 typ:      typ,
343                 names:    appendNames(nil, typ),
344                 constVal: constVal,
345                 obj:      obj,
346                 methods:  accessibleMethods(typ, qpos.info.Pkg),
347                 fields:   accessibleFields(typ, qpos.info.Pkg),
348         }, nil
349 }
350
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
374 type describeValueResult struct {
375         qpos     *queryPos
376         expr     ast.Expr       // query node
377         typ      types.Type     // type of expression
378         names    []*types.Named // named types within typ
379         constVal constant.Value // value of expression, if constant
380         obj      types.Object   // var/func/const object, if expr was Ident
381         methods  []*types.Selection
382         fields   []describeField
383 }
384
385 func (r *describeValueResult) PrintPlain(printf printfFunc) {
386         var prefix, suffix string
387         if r.constVal != nil {
388                 suffix = fmt.Sprintf(" of value %s", r.constVal)
389         }
390         switch obj := r.obj.(type) {
391         case *types.Func:
392                 if recv := obj.Type().(*types.Signature).Recv(); recv != nil {
393                         if _, ok := recv.Type().Underlying().(*types.Interface); ok {
394                                 prefix = "interface method "
395                         } else {
396                                 prefix = "method "
397                         }
398                 }
399         }
400
401         // Describe the expression.
402         if r.obj != nil {
403                 if r.obj.Pos() == r.expr.Pos() {
404                         // defining ident
405                         printf(r.expr, "definition of %s%s%s", prefix, r.qpos.objectString(r.obj), suffix)
406                 } else {
407                         // referring ident
408                         printf(r.expr, "reference to %s%s%s", prefix, r.qpos.objectString(r.obj), suffix)
409                         if def := r.obj.Pos(); def != token.NoPos {
410                                 printf(def, "defined here")
411                         }
412                 }
413         } else {
414                 desc := astutil.NodeDescription(r.expr)
415                 if suffix != "" {
416                         // constant expression
417                         printf(r.expr, "%s%s", desc, suffix)
418                 } else {
419                         // non-constant expression
420                         printf(r.expr, "%s of type %s", desc, r.qpos.typeString(r.typ))
421                 }
422         }
423
424         printMethods(printf, r.expr, r.methods)
425         printFields(printf, r.expr, r.fields)
426         printNamedTypes(printf, r.expr, r.names)
427 }
428
429 func (r *describeValueResult) JSON(fset *token.FileSet) []byte {
430         var value, objpos string
431         if r.constVal != nil {
432                 value = r.constVal.String()
433         }
434         if r.obj != nil {
435                 objpos = fset.Position(r.obj.Pos()).String()
436         }
437
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
446         return toJSON(&serial.Describe{
447                 Desc:   astutil.NodeDescription(r.expr),
448                 Pos:    fset.Position(r.expr.Pos()).String(),
449                 Detail: "value",
450                 Value: &serial.DescribeValue{
451                         Type:     r.qpos.typeString(r.typ),
452                         TypesPos: typesPos,
453                         Value:    value,
454                         ObjPos:   objpos,
455                 },
456         })
457 }
458
459 // ---- TYPE ------------------------------------------------------------
460
461 func describeType(qpos *queryPos, path []ast.Node) (*describeTypeResult, error) {
462         var description string
463         var typ types.Type
464         switch n := path[0].(type) {
465         case *ast.Ident:
466                 obj := qpos.info.ObjectOf(n).(*types.TypeName)
467                 typ = obj.Type()
468                 if isAlias(obj) {
469                         description = "alias of "
470                 } else if obj.Pos() == n.Pos() {
471                         description = "definition of " // (Named type)
472                 } else if _, ok := typ.(*types.Basic); ok {
473                         description = "reference to built-in "
474                 } else {
475                         description = "reference to " // (Named type)
476                 }
477
478         case ast.Expr:
479                 typ = qpos.info.TypeOf(n)
480
481         default:
482                 // Unreachable?
483                 return nil, fmt.Errorf("unexpected AST for type: %T", n)
484         }
485
486         description = description + "type " + qpos.typeString(typ)
487
488         // Show sizes for structs and named types (it's fairly obvious for others).
489         switch typ.(type) {
490         case *types.Named, *types.Struct:
491                 szs := types.StdSizes{WordSize: 8, MaxAlign: 8} // assume amd64
492                 description = fmt.Sprintf("%s (size %d, align %d)", description,
493                         szs.Sizeof(typ), szs.Alignof(typ))
494         }
495
496         return &describeTypeResult{
497                 qpos:        qpos,
498                 node:        path[0],
499                 description: description,
500                 typ:         typ,
501                 methods:     accessibleMethods(typ, qpos.info.Pkg),
502                 fields:      accessibleFields(typ, qpos.info.Pkg),
503         }, nil
504 }
505
506 type describeTypeResult struct {
507         qpos        *queryPos
508         node        ast.Node
509         description string
510         typ         types.Type
511         methods     []*types.Selection
512         fields      []describeField
513 }
514
515 type describeField struct {
516         implicits []*types.Named
517         field     *types.Var
518 }
519
520 func printMethods(printf printfFunc, node ast.Node, methods []*types.Selection) {
521         if len(methods) > 0 {
522                 printf(node, "Methods:")
523         }
524         for _, meth := range methods {
525                 // Print the method type relative to the package
526                 // in which it was defined, not the query package,
527                 printf(meth.Obj(), "\t%s",
528                         types.SelectionString(meth, types.RelativeTo(meth.Obj().Pkg())))
529         }
530 }
531
532 func printFields(printf printfFunc, node ast.Node, fields []describeField) {
533         if len(fields) > 0 {
534                 printf(node, "Fields:")
535         }
536
537         // Align the names and the types (requires two passes).
538         var width int
539         var names []string
540         for _, f := range fields {
541                 var buf bytes.Buffer
542                 for _, fld := range f.implicits {
543                         buf.WriteString(fld.Obj().Name())
544                         buf.WriteByte('.')
545                 }
546                 buf.WriteString(f.field.Name())
547                 name := buf.String()
548                 if n := utf8.RuneCountInString(name); n > width {
549                         width = n
550                 }
551                 names = append(names, name)
552         }
553
554         for i, f := range fields {
555                 // Print the field type relative to the package
556                 // in which it was defined, not the query package,
557                 printf(f.field, "\t%*s %s", -width, names[i],
558                         types.TypeString(f.field.Type(), types.RelativeTo(f.field.Pkg())))
559         }
560 }
561
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
575 func (r *describeTypeResult) PrintPlain(printf printfFunc) {
576         printf(r.node, "%s", r.description)
577
578         // Show the underlying type for a reference to a named type.
579         if nt, ok := r.typ.(*types.Named); ok && r.node.Pos() != nt.Obj().Pos() {
580                 // TODO(adonovan): improve display of complex struct/interface types.
581                 printf(nt.Obj(), "defined as %s", r.qpos.typeString(nt.Underlying()))
582         }
583
584         printMethods(printf, r.node, r.methods)
585         if len(r.methods) == 0 {
586                 // Only report null result for type kinds
587                 // capable of bearing methods.
588                 switch r.typ.(type) {
589                 case *types.Interface, *types.Struct, *types.Named:
590                         printf(r.node, "No methods.")
591                 }
592         }
593
594         printFields(printf, r.node, r.fields)
595 }
596
597 func (r *describeTypeResult) JSON(fset *token.FileSet) []byte {
598         var namePos, nameDef string
599         if nt, ok := r.typ.(*types.Named); ok {
600                 namePos = fset.Position(nt.Obj().Pos()).String()
601                 nameDef = nt.Underlying().String()
602         }
603         return toJSON(&serial.Describe{
604                 Desc:   r.description,
605                 Pos:    fset.Position(r.node.Pos()).String(),
606                 Detail: "type",
607                 Type: &serial.DescribeType{
608                         Type:    r.qpos.typeString(r.typ),
609                         NamePos: namePos,
610                         NameDef: nameDef,
611                         Methods: methodsToSerial(r.qpos.info.Pkg, r.methods, fset),
612                 },
613         })
614 }
615
616 // ---- PACKAGE ------------------------------------------------------------
617
618 func describePackage(qpos *queryPos, path []ast.Node) (*describePackageResult, error) {
619         var description string
620         var pkg *types.Package
621         switch n := path[0].(type) {
622         case *ast.ImportSpec:
623                 var obj types.Object
624                 if n.Name != nil {
625                         obj = qpos.info.Defs[n.Name]
626                 } else {
627                         obj = qpos.info.Implicits[n]
628                 }
629                 pkgname, _ := obj.(*types.PkgName)
630                 if pkgname == nil {
631                         return nil, fmt.Errorf("can't import package %s", n.Path.Value)
632                 }
633                 pkg = pkgname.Imported()
634                 description = fmt.Sprintf("import of package %q", pkg.Path())
635
636         case *ast.Ident:
637                 if _, isDef := path[1].(*ast.File); isDef {
638                         // e.g. package id
639                         pkg = qpos.info.Pkg
640                         description = fmt.Sprintf("definition of package %q", pkg.Path())
641                 } else {
642                         // e.g. import id "..."
643                         //  or  id.F()
644                         pkg = qpos.info.ObjectOf(n).(*types.PkgName).Imported()
645                         description = fmt.Sprintf("reference to package %q", pkg.Path())
646                 }
647
648         default:
649                 // Unreachable?
650                 return nil, fmt.Errorf("unexpected AST for package: %T", n)
651         }
652
653         var members []*describeMember
654         // NB: "unsafe" has no types.Package
655         if pkg != nil {
656                 // Enumerate the accessible package members
657                 // in lexicographic order.
658                 for _, name := range pkg.Scope().Names() {
659                         if pkg == qpos.info.Pkg || ast.IsExported(name) {
660                                 mem := pkg.Scope().Lookup(name)
661                                 var methods []*types.Selection
662                                 if mem, ok := mem.(*types.TypeName); ok {
663                                         methods = accessibleMethods(mem.Type(), qpos.info.Pkg)
664                                 }
665                                 members = append(members, &describeMember{
666                                         mem,
667                                         methods,
668                                 })
669
670                         }
671                 }
672         }
673
674         return &describePackageResult{qpos.fset, path[0], description, pkg, members}, nil
675 }
676
677 type describePackageResult struct {
678         fset        *token.FileSet
679         node        ast.Node
680         description string
681         pkg         *types.Package
682         members     []*describeMember // in lexicographic name order
683 }
684
685 type describeMember struct {
686         obj     types.Object
687         methods []*types.Selection // in types.MethodSet order
688 }
689
690 func (r *describePackageResult) PrintPlain(printf printfFunc) {
691         printf(r.node, "%s", r.description)
692
693         // Compute max width of name "column".
694         maxname := 0
695         for _, mem := range r.members {
696                 if l := len(mem.obj.Name()); l > maxname {
697                         maxname = l
698                 }
699         }
700
701         for _, mem := range r.members {
702                 printf(mem.obj, "\t%s", formatMember(mem.obj, maxname))
703                 for _, meth := range mem.methods {
704                         printf(meth.Obj(), "\t\t%s", types.SelectionString(meth, types.RelativeTo(r.pkg)))
705                 }
706         }
707 }
708
709 func formatMember(obj types.Object, maxname int) string {
710         qualifier := types.RelativeTo(obj.Pkg())
711         var buf bytes.Buffer
712         fmt.Fprintf(&buf, "%-5s %-*s", tokenOf(obj), maxname, obj.Name())
713         switch obj := obj.(type) {
714         case *types.Const:
715                 fmt.Fprintf(&buf, " %s = %s", types.TypeString(obj.Type(), qualifier), obj.Val())
716
717         case *types.Func:
718                 fmt.Fprintf(&buf, " %s", types.TypeString(obj.Type(), qualifier))
719
720         case *types.TypeName:
721                 typ := obj.Type()
722                 if isAlias(obj) {
723                         buf.WriteString(" = ")
724                 } else {
725                         buf.WriteByte(' ')
726                         typ = typ.Underlying()
727                 }
728                 var typestr string
729                 // Abbreviate long aggregate type names.
730                 switch typ := typ.(type) {
731                 case *types.Interface:
732                         if typ.NumMethods() > 1 {
733                                 typestr = "interface{...}"
734                         }
735                 case *types.Struct:
736                         if typ.NumFields() > 1 {
737                                 typestr = "struct{...}"
738                         }
739                 }
740                 if typestr == "" {
741                         typestr = types.TypeString(typ, qualifier)
742                 }
743                 buf.WriteString(typestr)
744
745         case *types.Var:
746                 fmt.Fprintf(&buf, " %s", types.TypeString(obj.Type(), qualifier))
747         }
748         return buf.String()
749 }
750
751 func (r *describePackageResult) JSON(fset *token.FileSet) []byte {
752         var members []*serial.DescribeMember
753         for _, mem := range r.members {
754                 obj := mem.obj
755                 typ := obj.Type()
756                 var val string
757                 var alias string
758                 switch obj := obj.(type) {
759                 case *types.Const:
760                         val = obj.Val().String()
761                 case *types.TypeName:
762                         if isAlias(obj) {
763                                 alias = "= " // kludgy
764                         } else {
765                                 typ = typ.Underlying()
766                         }
767                 }
768                 members = append(members, &serial.DescribeMember{
769                         Name:    obj.Name(),
770                         Type:    alias + typ.String(),
771                         Value:   val,
772                         Pos:     fset.Position(obj.Pos()).String(),
773                         Kind:    tokenOf(obj),
774                         Methods: methodsToSerial(r.pkg, mem.methods, fset),
775                 })
776         }
777         return toJSON(&serial.Describe{
778                 Desc:   r.description,
779                 Pos:    fset.Position(r.node.Pos()).String(),
780                 Detail: "package",
781                 Package: &serial.DescribePackage{
782                         Path:    r.pkg.Path(),
783                         Members: members,
784                 },
785         })
786 }
787
788 func tokenOf(o types.Object) string {
789         switch o.(type) {
790         case *types.Func:
791                 return "func"
792         case *types.Var:
793                 return "var"
794         case *types.TypeName:
795                 return "type"
796         case *types.Const:
797                 return "const"
798         case *types.PkgName:
799                 return "package"
800         case *types.Builtin:
801                 return "builtin" // e.g. when describing package "unsafe"
802         case *types.Nil:
803                 return "nil"
804         case *types.Label:
805                 return "label"
806         }
807         panic(o)
808 }
809
810 // ---- STATEMENT ------------------------------------------------------------
811
812 func describeStmt(qpos *queryPos, path []ast.Node) (*describeStmtResult, error) {
813         var description string
814         switch n := path[0].(type) {
815         case *ast.Ident:
816                 if qpos.info.Defs[n] != nil {
817                         description = "labelled statement"
818                 } else {
819                         description = "reference to labelled statement"
820                 }
821
822         default:
823                 // Nothing much to say about statements.
824                 description = astutil.NodeDescription(n)
825         }
826         return &describeStmtResult{qpos.fset, path[0], description}, nil
827 }
828
829 type describeStmtResult struct {
830         fset        *token.FileSet
831         node        ast.Node
832         description string
833 }
834
835 func (r *describeStmtResult) PrintPlain(printf printfFunc) {
836         printf(r.node, "%s", r.description)
837 }
838
839 func (r *describeStmtResult) JSON(fset *token.FileSet) []byte {
840         return toJSON(&serial.Describe{
841                 Desc:   r.description,
842                 Pos:    fset.Position(r.node.Pos()).String(),
843                 Detail: "unknown",
844         })
845 }
846
847 // ------------------- Utilities -------------------
848
849 // pathToString returns a string containing the concrete types of the
850 // nodes in path.
851 func pathToString(path []ast.Node) string {
852         var buf bytes.Buffer
853         fmt.Fprint(&buf, "[")
854         for i, n := range path {
855                 if i > 0 {
856                         fmt.Fprint(&buf, " ")
857                 }
858                 fmt.Fprint(&buf, strings.TrimPrefix(fmt.Sprintf("%T", n), "*ast."))
859         }
860         fmt.Fprint(&buf, "]")
861         return buf.String()
862 }
863
864 func accessibleMethods(t types.Type, from *types.Package) []*types.Selection {
865         var methods []*types.Selection
866         for _, meth := range typeutil.IntuitiveMethodSet(t, nil) {
867                 if isAccessibleFrom(meth.Obj(), from) {
868                         methods = append(methods, meth)
869                 }
870         }
871         return methods
872 }
873
874 // accessibleFields returns the set of accessible
875 // field selections on a value of type recv.
876 func accessibleFields(recv types.Type, from *types.Package) []describeField {
877         wantField := func(f *types.Var) bool {
878                 if !isAccessibleFrom(f, from) {
879                         return false
880                 }
881                 // Check that the field is not shadowed.
882                 obj, _, _ := types.LookupFieldOrMethod(recv, true, f.Pkg(), f.Name())
883                 return obj == f
884         }
885
886         var fields []describeField
887         var visit func(t types.Type, stack []*types.Named)
888         visit = func(t types.Type, stack []*types.Named) {
889                 tStruct, ok := deref(t).Underlying().(*types.Struct)
890                 if !ok {
891                         return
892                 }
893         fieldloop:
894                 for i := 0; i < tStruct.NumFields(); i++ {
895                         f := tStruct.Field(i)
896
897                         // Handle recursion through anonymous fields.
898                         if f.Anonymous() {
899                                 tf := f.Type()
900                                 if ptr, ok := tf.(*types.Pointer); ok {
901                                         tf = ptr.Elem()
902                                 }
903                                 if named, ok := tf.(*types.Named); ok { // (be defensive)
904                                         // If we've already visited this named type
905                                         // on this path, break the cycle.
906                                         for _, x := range stack {
907                                                 if x == named {
908                                                         continue fieldloop
909                                                 }
910                                         }
911                                         visit(f.Type(), append(stack, named))
912                                 }
913                         }
914
915                         // Save accessible fields.
916                         if wantField(f) {
917                                 fields = append(fields, describeField{
918                                         implicits: append([]*types.Named(nil), stack...),
919                                         field:     f,
920                                 })
921                         }
922                 }
923         }
924         visit(recv, nil)
925
926         return fields
927 }
928
929 func isAccessibleFrom(obj types.Object, pkg *types.Package) bool {
930         return ast.IsExported(obj.Name()) || obj.Pkg() == pkg
931 }
932
933 func methodsToSerial(this *types.Package, methods []*types.Selection, fset *token.FileSet) []serial.DescribeMethod {
934         qualifier := types.RelativeTo(this)
935         var jmethods []serial.DescribeMethod
936         for _, meth := range methods {
937                 var ser serial.DescribeMethod
938                 if meth != nil { // may contain nils when called by implements (on a method)
939                         ser = serial.DescribeMethod{
940                                 Name: types.SelectionString(meth, qualifier),
941                                 Pos:  fset.Position(meth.Obj().Pos()).String(),
942                         }
943                 }
944                 jmethods = append(jmethods, ser)
945         }
946         return jmethods
947 }