github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/oracle/describe15.go (about)

     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  // +build go1.5,!go1.6
     6  
     7  package oracle
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  	"go/ast"
    13  	exact "go/constant"
    14  	"go/token"
    15  	"go/types"
    16  	"log"
    17  	"os"
    18  	"strings"
    19  
    20  	"golang.org/x/tools/go/ast/astutil"
    21  	"golang.org/x/tools/go/loader"
    22  	"golang.org/x/tools/go/types/typeutil"
    23  	"golang.org/x/tools/oracle/serial"
    24  )
    25  
    26  // describe describes the syntax node denoted by the query position,
    27  // including:
    28  // - its syntactic category
    29  // - the definition of its referent (for identifiers) [now redundant]
    30  // - its type and method set (for an expression or type expression)
    31  //
    32  func describe(q *Query) error {
    33  	lconf := loader.Config{Build: q.Build}
    34  	allowErrors(&lconf)
    35  
    36  	if _, err := importQueryPackage(q.Pos, &lconf); err != nil {
    37  		return err
    38  	}
    39  
    40  	// Load/parse/type-check the program.
    41  	lprog, err := lconf.Load()
    42  	if err != nil {
    43  		return err
    44  	}
    45  	q.Fset = lprog.Fset
    46  
    47  	qpos, err := parseQueryPos(lprog, q.Pos, true) // (need exact pos)
    48  	if err != nil {
    49  		return err
    50  	}
    51  
    52  	if false { // debugging
    53  		fprintf(os.Stderr, lprog.Fset, qpos.path[0], "you selected: %s %s",
    54  			astutil.NodeDescription(qpos.path[0]), pathToString(qpos.path))
    55  	}
    56  
    57  	path, action := findInterestingNode(qpos.info, qpos.path)
    58  	switch action {
    59  	case actionExpr:
    60  		q.result, err = describeValue(qpos, path)
    61  
    62  	case actionType:
    63  		q.result, err = describeType(qpos, path)
    64  
    65  	case actionPackage:
    66  		q.result, err = describePackage(qpos, path)
    67  
    68  	case actionStmt:
    69  		q.result, err = describeStmt(qpos, path)
    70  
    71  	case actionUnknown:
    72  		q.result = &describeUnknownResult{path[0]}
    73  
    74  	default:
    75  		panic(action) // unreachable
    76  	}
    77  	return err
    78  }
    79  
    80  type describeUnknownResult struct {
    81  	node ast.Node
    82  }
    83  
    84  func (r *describeUnknownResult) display(printf printfFunc) {
    85  	// Nothing much to say about misc syntax.
    86  	printf(r.node, "%s", astutil.NodeDescription(r.node))
    87  }
    88  
    89  func (r *describeUnknownResult) toSerial(res *serial.Result, fset *token.FileSet) {
    90  	res.Describe = &serial.Describe{
    91  		Desc: astutil.NodeDescription(r.node),
    92  		Pos:  fset.Position(r.node.Pos()).String(),
    93  	}
    94  }
    95  
    96  type action int
    97  
    98  const (
    99  	actionUnknown action = iota // None of the below
   100  	actionExpr                  // FuncDecl, true Expr or Ident(types.{Const,Var})
   101  	actionType                  // type Expr or Ident(types.TypeName).
   102  	actionStmt                  // Stmt or Ident(types.Label)
   103  	actionPackage               // Ident(types.Package) or ImportSpec
   104  )
   105  
   106  // findInterestingNode classifies the syntax node denoted by path as one of:
   107  //    - an expression, part of an expression or a reference to a constant
   108  //      or variable;
   109  //    - a type, part of a type, or a reference to a named type;
   110  //    - a statement, part of a statement, or a label referring to a statement;
   111  //    - part of a package declaration or import spec.
   112  //    - none of the above.
   113  // and returns the most "interesting" associated node, which may be
   114  // the same node, an ancestor or a descendent.
   115  //
   116  func findInterestingNode(pkginfo *loader.PackageInfo, path []ast.Node) ([]ast.Node, action) {
   117  	// TODO(adonovan): integrate with go/types/stdlib_test.go and
   118  	// apply this to every AST node we can find to make sure it
   119  	// doesn't crash.
   120  
   121  	// TODO(adonovan): audit for ParenExpr safety, esp. since we
   122  	// traverse up and down.
   123  
   124  	// TODO(adonovan): if the users selects the "." in
   125  	// "fmt.Fprintf()", they'll get an ambiguous selection error;
   126  	// we won't even reach here.  Can we do better?
   127  
   128  	// TODO(adonovan): describing a field within 'type T struct {...}'
   129  	// describes the (anonymous) struct type and concludes "no methods".
   130  	// We should ascend to the enclosing type decl, if any.
   131  
   132  	for len(path) > 0 {
   133  		switch n := path[0].(type) {
   134  		case *ast.GenDecl:
   135  			if len(n.Specs) == 1 {
   136  				// Descend to sole {Import,Type,Value}Spec child.
   137  				path = append([]ast.Node{n.Specs[0]}, path...)
   138  				continue
   139  			}
   140  			return path, actionUnknown // uninteresting
   141  
   142  		case *ast.FuncDecl:
   143  			// Descend to function name.
   144  			path = append([]ast.Node{n.Name}, path...)
   145  			continue
   146  
   147  		case *ast.ImportSpec:
   148  			return path, actionPackage
   149  
   150  		case *ast.ValueSpec:
   151  			if len(n.Names) == 1 {
   152  				// Descend to sole Ident child.
   153  				path = append([]ast.Node{n.Names[0]}, path...)
   154  				continue
   155  			}
   156  			return path, actionUnknown // uninteresting
   157  
   158  		case *ast.TypeSpec:
   159  			// Descend to type name.
   160  			path = append([]ast.Node{n.Name}, path...)
   161  			continue
   162  
   163  		case ast.Stmt:
   164  			return path, actionStmt
   165  
   166  		case *ast.ArrayType,
   167  			*ast.StructType,
   168  			*ast.FuncType,
   169  			*ast.InterfaceType,
   170  			*ast.MapType,
   171  			*ast.ChanType:
   172  			return path, actionType
   173  
   174  		case *ast.Comment, *ast.CommentGroup, *ast.File, *ast.KeyValueExpr, *ast.CommClause:
   175  			return path, actionUnknown // uninteresting
   176  
   177  		case *ast.Ellipsis:
   178  			// Continue to enclosing node.
   179  			// e.g. [...]T in ArrayType
   180  			//      f(x...) in CallExpr
   181  			//      f(x...T) in FuncType
   182  
   183  		case *ast.Field:
   184  			// TODO(adonovan): this needs more thought,
   185  			// since fields can be so many things.
   186  			if len(n.Names) == 1 {
   187  				// Descend to sole Ident child.
   188  				path = append([]ast.Node{n.Names[0]}, path...)
   189  				continue
   190  			}
   191  			// Zero names (e.g. anon field in struct)
   192  			// or multiple field or param names:
   193  			// continue to enclosing field list.
   194  
   195  		case *ast.FieldList:
   196  			// Continue to enclosing node:
   197  			// {Struct,Func,Interface}Type or FuncDecl.
   198  
   199  		case *ast.BasicLit:
   200  			if _, ok := path[1].(*ast.ImportSpec); ok {
   201  				return path[1:], actionPackage
   202  			}
   203  			return path, actionExpr
   204  
   205  		case *ast.SelectorExpr:
   206  			// TODO(adonovan): use Selections info directly.
   207  			if pkginfo.Uses[n.Sel] == nil {
   208  				// TODO(adonovan): is this reachable?
   209  				return path, actionUnknown
   210  			}
   211  			// Descend to .Sel child.
   212  			path = append([]ast.Node{n.Sel}, path...)
   213  			continue
   214  
   215  		case *ast.Ident:
   216  			switch pkginfo.ObjectOf(n).(type) {
   217  			case *types.PkgName:
   218  				return path, actionPackage
   219  
   220  			case *types.Const:
   221  				return path, actionExpr
   222  
   223  			case *types.Label:
   224  				return path, actionStmt
   225  
   226  			case *types.TypeName:
   227  				return path, actionType
   228  
   229  			case *types.Var:
   230  				// For x in 'struct {x T}', return struct type, for now.
   231  				if _, ok := path[1].(*ast.Field); ok {
   232  					_ = path[2].(*ast.FieldList) // assertion
   233  					if _, ok := path[3].(*ast.StructType); ok {
   234  						return path[3:], actionType
   235  					}
   236  				}
   237  				return path, actionExpr
   238  
   239  			case *types.Func:
   240  				return path, actionExpr
   241  
   242  			case *types.Builtin:
   243  				// For reference to built-in function, return enclosing call.
   244  				path = path[1:] // ascend to enclosing function call
   245  				continue
   246  
   247  			case *types.Nil:
   248  				return path, actionExpr
   249  			}
   250  
   251  			// No object.
   252  			switch path[1].(type) {
   253  			case *ast.SelectorExpr:
   254  				// Return enclosing selector expression.
   255  				return path[1:], actionExpr
   256  
   257  			case *ast.Field:
   258  				// TODO(adonovan): test this.
   259  				// e.g. all f in:
   260  				//  struct { f, g int }
   261  				//  interface { f() }
   262  				//  func (f T) method(f, g int) (f, g bool)
   263  				//
   264  				// switch path[3].(type) {
   265  				// case *ast.FuncDecl:
   266  				// case *ast.StructType:
   267  				// case *ast.InterfaceType:
   268  				// }
   269  				//
   270  				// return path[1:], actionExpr
   271  				//
   272  				// Unclear what to do with these.
   273  				// Struct.Fields             -- field
   274  				// Interface.Methods         -- field
   275  				// FuncType.{Params.Results} -- actionExpr
   276  				// FuncDecl.Recv             -- actionExpr
   277  
   278  			case *ast.File:
   279  				// 'package foo'
   280  				return path, actionPackage
   281  
   282  			case *ast.ImportSpec:
   283  				// TODO(adonovan): fix: why no package object? go/types bug?
   284  				return path[1:], actionPackage
   285  
   286  			default:
   287  				// e.g. blank identifier
   288  				// or y in "switch y := x.(type)"
   289  				// or code in a _test.go file that's not part of the package.
   290  				log.Printf("unknown reference %s in %T\n", n, path[1])
   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  	constVal := qpos.info.Types[expr].Value
   332  
   333  	return &describeValueResult{
   334  		qpos:     qpos,
   335  		expr:     expr,
   336  		typ:      typ,
   337  		constVal: constVal,
   338  		obj:      obj,
   339  	}, nil
   340  }
   341  
   342  type describeValueResult struct {
   343  	qpos     *queryPos
   344  	expr     ast.Expr     // query node
   345  	typ      types.Type   // type of expression
   346  	constVal exact.Value  // value of expression, if constant
   347  	obj      types.Object // var/func/const object, if expr was Ident
   348  }
   349  
   350  func (r *describeValueResult) display(printf printfFunc) {
   351  	var prefix, suffix string
   352  	if r.constVal != nil {
   353  		suffix = fmt.Sprintf(" of constant value %s", constValString(r.constVal))
   354  	}
   355  	switch obj := r.obj.(type) {
   356  	case *types.Func:
   357  		if recv := obj.Type().(*types.Signature).Recv(); recv != nil {
   358  			if _, ok := recv.Type().Underlying().(*types.Interface); ok {
   359  				prefix = "interface method "
   360  			} else {
   361  				prefix = "method "
   362  			}
   363  		}
   364  	}
   365  
   366  	// Describe the expression.
   367  	if r.obj != nil {
   368  		if r.obj.Pos() == r.expr.Pos() {
   369  			// defining ident
   370  			printf(r.expr, "definition of %s%s%s", prefix, r.qpos.objectString(r.obj), suffix)
   371  		} else {
   372  			// referring ident
   373  			printf(r.expr, "reference to %s%s%s", prefix, r.qpos.objectString(r.obj), suffix)
   374  			if def := r.obj.Pos(); def != token.NoPos {
   375  				printf(def, "defined here")
   376  			}
   377  		}
   378  	} else {
   379  		desc := astutil.NodeDescription(r.expr)
   380  		if suffix != "" {
   381  			// constant expression
   382  			printf(r.expr, "%s%s", desc, suffix)
   383  		} else {
   384  			// non-constant expression
   385  			printf(r.expr, "%s of type %s", desc, r.qpos.typeString(r.typ))
   386  		}
   387  	}
   388  }
   389  
   390  func (r *describeValueResult) toSerial(res *serial.Result, fset *token.FileSet) {
   391  	var value, objpos string
   392  	if r.constVal != nil {
   393  		value = r.constVal.String()
   394  	}
   395  	if r.obj != nil {
   396  		objpos = fset.Position(r.obj.Pos()).String()
   397  	}
   398  
   399  	res.Describe = &serial.Describe{
   400  		Desc:   astutil.NodeDescription(r.expr),
   401  		Pos:    fset.Position(r.expr.Pos()).String(),
   402  		Detail: "value",
   403  		Value: &serial.DescribeValue{
   404  			Type:   r.qpos.typeString(r.typ),
   405  			Value:  value,
   406  			ObjPos: objpos,
   407  		},
   408  	}
   409  }
   410  
   411  // ---- TYPE ------------------------------------------------------------
   412  
   413  func describeType(qpos *queryPos, path []ast.Node) (*describeTypeResult, error) {
   414  	var description string
   415  	var t types.Type
   416  	switch n := path[0].(type) {
   417  	case *ast.Ident:
   418  		t = qpos.info.TypeOf(n)
   419  		switch t := t.(type) {
   420  		case *types.Basic:
   421  			description = "reference to built-in "
   422  
   423  		case *types.Named:
   424  			isDef := t.Obj().Pos() == n.Pos() // see caveats at isDef above
   425  			if isDef {
   426  				description = "definition of "
   427  			} else {
   428  				description = "reference to "
   429  			}
   430  		}
   431  
   432  	case ast.Expr:
   433  		t = qpos.info.TypeOf(n)
   434  
   435  	default:
   436  		// Unreachable?
   437  		return nil, fmt.Errorf("unexpected AST for type: %T", n)
   438  	}
   439  
   440  	description = description + "type " + qpos.typeString(t)
   441  
   442  	// Show sizes for structs and named types (it's fairly obvious for others).
   443  	switch t.(type) {
   444  	case *types.Named, *types.Struct:
   445  		szs := types.StdSizes{8, 8} // assume amd64
   446  		description = fmt.Sprintf("%s (size %d, align %d)", description,
   447  			szs.Sizeof(t), szs.Alignof(t))
   448  	}
   449  
   450  	return &describeTypeResult{
   451  		qpos:        qpos,
   452  		node:        path[0],
   453  		description: description,
   454  		typ:         t,
   455  		methods:     accessibleMethods(t, qpos.info.Pkg),
   456  	}, nil
   457  }
   458  
   459  type describeTypeResult struct {
   460  	qpos        *queryPos
   461  	node        ast.Node
   462  	description string
   463  	typ         types.Type
   464  	methods     []*types.Selection
   465  }
   466  
   467  func (r *describeTypeResult) display(printf printfFunc) {
   468  	printf(r.node, "%s", r.description)
   469  
   470  	// Show the underlying type for a reference to a named type.
   471  	if nt, ok := r.typ.(*types.Named); ok && r.node.Pos() != nt.Obj().Pos() {
   472  		printf(nt.Obj(), "defined as %s", r.qpos.typeString(nt.Underlying()))
   473  	}
   474  
   475  	// Print the method set, if the type kind is capable of bearing methods.
   476  	switch r.typ.(type) {
   477  	case *types.Interface, *types.Struct, *types.Named:
   478  		if len(r.methods) > 0 {
   479  			printf(r.node, "Method set:")
   480  			for _, meth := range r.methods {
   481  				// TODO(adonovan): print these relative
   482  				// to the owning package, not the
   483  				// query package.
   484  				printf(meth.Obj(), "\t%s", r.qpos.selectionString(meth))
   485  			}
   486  		} else {
   487  			printf(r.node, "No methods.")
   488  		}
   489  	}
   490  }
   491  
   492  func (r *describeTypeResult) toSerial(res *serial.Result, fset *token.FileSet) {
   493  	var namePos, nameDef string
   494  	if nt, ok := r.typ.(*types.Named); ok {
   495  		namePos = fset.Position(nt.Obj().Pos()).String()
   496  		nameDef = nt.Underlying().String()
   497  	}
   498  	res.Describe = &serial.Describe{
   499  		Desc:   r.description,
   500  		Pos:    fset.Position(r.node.Pos()).String(),
   501  		Detail: "type",
   502  		Type: &serial.DescribeType{
   503  			Type:    r.qpos.typeString(r.typ),
   504  			NamePos: namePos,
   505  			NameDef: nameDef,
   506  			Methods: methodsToSerial(r.qpos.info.Pkg, r.methods, fset),
   507  		},
   508  	}
   509  }
   510  
   511  // ---- PACKAGE ------------------------------------------------------------
   512  
   513  func describePackage(qpos *queryPos, path []ast.Node) (*describePackageResult, error) {
   514  	var description string
   515  	var pkg *types.Package
   516  	switch n := path[0].(type) {
   517  	case *ast.ImportSpec:
   518  		var obj types.Object
   519  		if n.Name != nil {
   520  			obj = qpos.info.Defs[n.Name]
   521  		} else {
   522  			obj = qpos.info.Implicits[n]
   523  		}
   524  		pkgname, _ := obj.(*types.PkgName)
   525  		if pkgname == nil {
   526  			return nil, fmt.Errorf("can't import package %s", n.Path.Value)
   527  		}
   528  		pkg = pkgname.Imported()
   529  		description = fmt.Sprintf("import of package %q", pkg.Path())
   530  
   531  	case *ast.Ident:
   532  		if _, isDef := path[1].(*ast.File); isDef {
   533  			// e.g. package id
   534  			pkg = qpos.info.Pkg
   535  			description = fmt.Sprintf("definition of package %q", pkg.Path())
   536  		} else {
   537  			// e.g. import id "..."
   538  			//  or  id.F()
   539  			pkg = qpos.info.ObjectOf(n).(*types.PkgName).Imported()
   540  			description = fmt.Sprintf("reference to package %q", pkg.Path())
   541  		}
   542  
   543  	default:
   544  		// Unreachable?
   545  		return nil, fmt.Errorf("unexpected AST for package: %T", n)
   546  	}
   547  
   548  	var members []*describeMember
   549  	// NB: "unsafe" has no types.Package
   550  	if pkg != nil {
   551  		// Enumerate the accessible package members
   552  		// in lexicographic order.
   553  		for _, name := range pkg.Scope().Names() {
   554  			if pkg == qpos.info.Pkg || ast.IsExported(name) {
   555  				mem := pkg.Scope().Lookup(name)
   556  				var methods []*types.Selection
   557  				if mem, ok := mem.(*types.TypeName); ok {
   558  					methods = accessibleMethods(mem.Type(), qpos.info.Pkg)
   559  				}
   560  				members = append(members, &describeMember{
   561  					mem,
   562  					methods,
   563  				})
   564  
   565  			}
   566  		}
   567  	}
   568  
   569  	return &describePackageResult{qpos.fset, path[0], description, pkg, members}, nil
   570  }
   571  
   572  type describePackageResult struct {
   573  	fset        *token.FileSet
   574  	node        ast.Node
   575  	description string
   576  	pkg         *types.Package
   577  	members     []*describeMember // in lexicographic name order
   578  }
   579  
   580  type describeMember struct {
   581  	obj     types.Object
   582  	methods []*types.Selection // in types.MethodSet order
   583  }
   584  
   585  func (r *describePackageResult) display(printf printfFunc) {
   586  	printf(r.node, "%s", r.description)
   587  
   588  	// Compute max width of name "column".
   589  	maxname := 0
   590  	for _, mem := range r.members {
   591  		if l := len(mem.obj.Name()); l > maxname {
   592  			maxname = l
   593  		}
   594  	}
   595  
   596  	for _, mem := range r.members {
   597  		printf(mem.obj, "\t%s", formatMember(mem.obj, maxname))
   598  		for _, meth := range mem.methods {
   599  			printf(meth.Obj(), "\t\t%s", types.SelectionString(meth, types.RelativeTo(r.pkg)))
   600  		}
   601  	}
   602  }
   603  
   604  func formatMember(obj types.Object, maxname int) string {
   605  	qualifier := types.RelativeTo(obj.Pkg())
   606  	var buf bytes.Buffer
   607  	fmt.Fprintf(&buf, "%-5s %-*s", tokenOf(obj), maxname, obj.Name())
   608  	switch obj := obj.(type) {
   609  	case *types.Const:
   610  		fmt.Fprintf(&buf, " %s = %s", types.TypeString(obj.Type(), qualifier), constValString(obj.Val()))
   611  
   612  	case *types.Func:
   613  		fmt.Fprintf(&buf, " %s", types.TypeString(obj.Type(), qualifier))
   614  
   615  	case *types.TypeName:
   616  		// Abbreviate long aggregate type names.
   617  		var abbrev string
   618  		switch t := obj.Type().Underlying().(type) {
   619  		case *types.Interface:
   620  			if t.NumMethods() > 1 {
   621  				abbrev = "interface{...}"
   622  			}
   623  		case *types.Struct:
   624  			if t.NumFields() > 1 {
   625  				abbrev = "struct{...}"
   626  			}
   627  		}
   628  		if abbrev == "" {
   629  			fmt.Fprintf(&buf, " %s", types.TypeString(obj.Type().Underlying(), qualifier))
   630  		} else {
   631  			fmt.Fprintf(&buf, " %s", abbrev)
   632  		}
   633  
   634  	case *types.Var:
   635  		fmt.Fprintf(&buf, " %s", types.TypeString(obj.Type(), qualifier))
   636  	}
   637  	return buf.String()
   638  }
   639  
   640  func (r *describePackageResult) toSerial(res *serial.Result, fset *token.FileSet) {
   641  	var members []*serial.DescribeMember
   642  	for _, mem := range r.members {
   643  		typ := mem.obj.Type()
   644  		var val string
   645  		switch mem := mem.obj.(type) {
   646  		case *types.Const:
   647  			val = constValString(mem.Val())
   648  		case *types.TypeName:
   649  			typ = typ.Underlying()
   650  		}
   651  		members = append(members, &serial.DescribeMember{
   652  			Name:    mem.obj.Name(),
   653  			Type:    typ.String(),
   654  			Value:   val,
   655  			Pos:     fset.Position(mem.obj.Pos()).String(),
   656  			Kind:    tokenOf(mem.obj),
   657  			Methods: methodsToSerial(r.pkg, mem.methods, fset),
   658  		})
   659  	}
   660  	res.Describe = &serial.Describe{
   661  		Desc:   r.description,
   662  		Pos:    fset.Position(r.node.Pos()).String(),
   663  		Detail: "package",
   664  		Package: &serial.DescribePackage{
   665  			Path:    r.pkg.Path(),
   666  			Members: members,
   667  		},
   668  	}
   669  }
   670  
   671  func tokenOf(o types.Object) string {
   672  	switch o.(type) {
   673  	case *types.Func:
   674  		return "func"
   675  	case *types.Var:
   676  		return "var"
   677  	case *types.TypeName:
   678  		return "type"
   679  	case *types.Const:
   680  		return "const"
   681  	case *types.PkgName:
   682  		return "package"
   683  	}
   684  	panic(o)
   685  }
   686  
   687  // ---- STATEMENT ------------------------------------------------------------
   688  
   689  func describeStmt(qpos *queryPos, path []ast.Node) (*describeStmtResult, error) {
   690  	var description string
   691  	switch n := path[0].(type) {
   692  	case *ast.Ident:
   693  		if qpos.info.Defs[n] != nil {
   694  			description = "labelled statement"
   695  		} else {
   696  			description = "reference to labelled statement"
   697  		}
   698  
   699  	default:
   700  		// Nothing much to say about statements.
   701  		description = astutil.NodeDescription(n)
   702  	}
   703  	return &describeStmtResult{qpos.fset, path[0], description}, nil
   704  }
   705  
   706  type describeStmtResult struct {
   707  	fset        *token.FileSet
   708  	node        ast.Node
   709  	description string
   710  }
   711  
   712  func (r *describeStmtResult) display(printf printfFunc) {
   713  	printf(r.node, "%s", r.description)
   714  }
   715  
   716  func (r *describeStmtResult) toSerial(res *serial.Result, fset *token.FileSet) {
   717  	res.Describe = &serial.Describe{
   718  		Desc:   r.description,
   719  		Pos:    fset.Position(r.node.Pos()).String(),
   720  		Detail: "unknown",
   721  	}
   722  }
   723  
   724  // ------------------- Utilities -------------------
   725  
   726  // pathToString returns a string containing the concrete types of the
   727  // nodes in path.
   728  func pathToString(path []ast.Node) string {
   729  	var buf bytes.Buffer
   730  	fmt.Fprint(&buf, "[")
   731  	for i, n := range path {
   732  		if i > 0 {
   733  			fmt.Fprint(&buf, " ")
   734  		}
   735  		fmt.Fprint(&buf, strings.TrimPrefix(fmt.Sprintf("%T", n), "*ast."))
   736  	}
   737  	fmt.Fprint(&buf, "]")
   738  	return buf.String()
   739  }
   740  
   741  func accessibleMethods(t types.Type, from *types.Package) []*types.Selection {
   742  	var methods []*types.Selection
   743  	for _, meth := range typeutil.IntuitiveMethodSet(t, nil) {
   744  		if isAccessibleFrom(meth.Obj(), from) {
   745  			methods = append(methods, meth)
   746  		}
   747  	}
   748  	return methods
   749  }
   750  
   751  func isAccessibleFrom(obj types.Object, pkg *types.Package) bool {
   752  	return ast.IsExported(obj.Name()) || obj.Pkg() == pkg
   753  }
   754  
   755  func methodsToSerial(this *types.Package, methods []*types.Selection, fset *token.FileSet) []serial.DescribeMethod {
   756  	qualifier := types.RelativeTo(this)
   757  	var jmethods []serial.DescribeMethod
   758  	for _, meth := range methods {
   759  		var ser serial.DescribeMethod
   760  		if meth != nil { // may contain nils when called by implements (on a method)
   761  			ser = serial.DescribeMethod{
   762  				Name: types.SelectionString(meth, qualifier),
   763  				Pos:  fset.Position(meth.Obj().Pos()).String(),
   764  			}
   765  		}
   766  		jmethods = append(jmethods, ser)
   767  	}
   768  	return jmethods
   769  }
   770  
   771  // constValString emulates Go 1.6's go/constant.ExactString well enough
   772  // to make the tests pass.  This is just a stopgap until we throw away
   773  // all the *15.go files.
   774  func constValString(v exact.Value) string {
   775  	if v.Kind() == exact.Float {
   776  		f, _ := exact.Float64Val(v)
   777  		return fmt.Sprintf("%g", f)
   778  	}
   779  	return v.String()
   780  }