github.com/gwaycc/gometalinter@v3.0.0+incompatible/_linters/src/honnef.co/go/tools/unused/unused.go (about)

     1  package unused // import "honnef.co/go/tools/unused"
     2  
     3  import (
     4  	"fmt"
     5  	"go/ast"
     6  	"go/token"
     7  	"go/types"
     8  	"io"
     9  	"path/filepath"
    10  	"strings"
    11  
    12  	"honnef.co/go/tools/lint"
    13  	. "honnef.co/go/tools/lint/lintdsl"
    14  
    15  	"golang.org/x/tools/go/packages"
    16  	"golang.org/x/tools/go/types/typeutil"
    17  )
    18  
    19  func NewLintChecker(c *Checker) *LintChecker {
    20  	l := &LintChecker{
    21  		c: c,
    22  	}
    23  	return l
    24  }
    25  
    26  type LintChecker struct {
    27  	c *Checker
    28  }
    29  
    30  func (*LintChecker) Name() string   { return "unused" }
    31  func (*LintChecker) Prefix() string { return "U" }
    32  
    33  func (l *LintChecker) Init(*lint.Program) {}
    34  func (l *LintChecker) Checks() []lint.Check {
    35  	return []lint.Check{
    36  		{ID: "U1000", FilterGenerated: true, Fn: l.Lint},
    37  	}
    38  }
    39  
    40  func typString(obj types.Object) string {
    41  	switch obj := obj.(type) {
    42  	case *types.Func:
    43  		return "func"
    44  	case *types.Var:
    45  		if obj.IsField() {
    46  			return "field"
    47  		}
    48  		return "var"
    49  	case *types.Const:
    50  		return "const"
    51  	case *types.TypeName:
    52  		return "type"
    53  	default:
    54  		// log.Printf("%T", obj)
    55  		return "identifier"
    56  	}
    57  }
    58  
    59  func (l *LintChecker) Lint(j *lint.Job) {
    60  	unused := l.c.Check(j.Program)
    61  	for _, u := range unused {
    62  		name := u.Obj.Name()
    63  		if sig, ok := u.Obj.Type().(*types.Signature); ok && sig.Recv() != nil {
    64  			switch sig.Recv().Type().(type) {
    65  			case *types.Named, *types.Pointer:
    66  				typ := types.TypeString(sig.Recv().Type(), func(*types.Package) string { return "" })
    67  				if len(typ) > 0 && typ[0] == '*' {
    68  					name = fmt.Sprintf("(%s).%s", typ, u.Obj.Name())
    69  				} else if len(typ) > 0 {
    70  					name = fmt.Sprintf("%s.%s", typ, u.Obj.Name())
    71  				}
    72  			}
    73  		}
    74  		j.Errorf(u.Obj, "%s %s is unused", typString(u.Obj), name)
    75  	}
    76  }
    77  
    78  type graph struct {
    79  	roots []*graphNode
    80  	nodes map[interface{}]*graphNode
    81  }
    82  
    83  func (g *graph) markUsedBy(obj, usedBy interface{}) {
    84  	objNode := g.getNode(obj)
    85  	usedByNode := g.getNode(usedBy)
    86  	if objNode.obj == usedByNode.obj {
    87  		return
    88  	}
    89  	usedByNode.uses[objNode] = struct{}{}
    90  }
    91  
    92  var labelCounter = 1
    93  
    94  func (g *graph) getNode(obj interface{}) *graphNode {
    95  	for {
    96  		if pt, ok := obj.(*types.Pointer); ok {
    97  			obj = pt.Elem()
    98  		} else {
    99  			break
   100  		}
   101  	}
   102  	_, ok := g.nodes[obj]
   103  	if !ok {
   104  		g.addObj(obj)
   105  	}
   106  
   107  	return g.nodes[obj]
   108  }
   109  
   110  func (g *graph) addObj(obj interface{}) {
   111  	if pt, ok := obj.(*types.Pointer); ok {
   112  		obj = pt.Elem()
   113  	}
   114  	node := &graphNode{obj: obj, uses: make(map[*graphNode]struct{}), n: labelCounter}
   115  	g.nodes[obj] = node
   116  	labelCounter++
   117  
   118  	if obj, ok := obj.(*types.Struct); ok {
   119  		n := obj.NumFields()
   120  		for i := 0; i < n; i++ {
   121  			field := obj.Field(i)
   122  			g.markUsedBy(obj, field)
   123  		}
   124  	}
   125  }
   126  
   127  type graphNode struct {
   128  	obj   interface{}
   129  	uses  map[*graphNode]struct{}
   130  	used  bool
   131  	quiet bool
   132  	n     int
   133  }
   134  
   135  type CheckMode int
   136  
   137  const (
   138  	CheckConstants CheckMode = 1 << iota
   139  	CheckFields
   140  	CheckFunctions
   141  	CheckTypes
   142  	CheckVariables
   143  
   144  	CheckAll = CheckConstants | CheckFields | CheckFunctions | CheckTypes | CheckVariables
   145  )
   146  
   147  type Unused struct {
   148  	Obj      types.Object
   149  	Position token.Position
   150  }
   151  
   152  type Checker struct {
   153  	Mode               CheckMode
   154  	WholeProgram       bool
   155  	ConsiderReflection bool
   156  	Debug              io.Writer
   157  
   158  	graph *graph
   159  
   160  	msCache      typeutil.MethodSetCache
   161  	prog         *lint.Program
   162  	topmostCache map[*types.Scope]*types.Scope
   163  	interfaces   []*types.Interface
   164  }
   165  
   166  func NewChecker(mode CheckMode) *Checker {
   167  	return &Checker{
   168  		Mode: mode,
   169  		graph: &graph{
   170  			nodes: make(map[interface{}]*graphNode),
   171  		},
   172  		topmostCache: make(map[*types.Scope]*types.Scope),
   173  	}
   174  }
   175  
   176  func (c *Checker) checkConstants() bool { return (c.Mode & CheckConstants) > 0 }
   177  func (c *Checker) checkFields() bool    { return (c.Mode & CheckFields) > 0 }
   178  func (c *Checker) checkFunctions() bool { return (c.Mode & CheckFunctions) > 0 }
   179  func (c *Checker) checkTypes() bool     { return (c.Mode & CheckTypes) > 0 }
   180  func (c *Checker) checkVariables() bool { return (c.Mode & CheckVariables) > 0 }
   181  
   182  func (c *Checker) markFields(typ types.Type) {
   183  	structType, ok := typ.Underlying().(*types.Struct)
   184  	if !ok {
   185  		return
   186  	}
   187  	n := structType.NumFields()
   188  	for i := 0; i < n; i++ {
   189  		field := structType.Field(i)
   190  		c.graph.markUsedBy(field, typ)
   191  	}
   192  }
   193  
   194  type Error struct {
   195  	Errors map[string][]error
   196  }
   197  
   198  func (e Error) Error() string {
   199  	return fmt.Sprintf("errors in %d packages", len(e.Errors))
   200  }
   201  
   202  func (c *Checker) Check(prog *lint.Program) []Unused {
   203  	var unused []Unused
   204  	c.prog = prog
   205  	if c.WholeProgram {
   206  		c.findExportedInterfaces()
   207  	}
   208  	for _, pkg := range prog.InitialPackages {
   209  		c.processDefs(pkg)
   210  		c.processUses(pkg)
   211  		c.processTypes(pkg)
   212  		c.processSelections(pkg)
   213  		c.processAST(pkg)
   214  	}
   215  
   216  	for _, node := range c.graph.nodes {
   217  		obj, ok := node.obj.(types.Object)
   218  		if !ok {
   219  			continue
   220  		}
   221  		typNode, ok := c.graph.nodes[obj.Type()]
   222  		if !ok {
   223  			continue
   224  		}
   225  		node.uses[typNode] = struct{}{}
   226  	}
   227  
   228  	roots := map[*graphNode]struct{}{}
   229  	for _, root := range c.graph.roots {
   230  		roots[root] = struct{}{}
   231  	}
   232  	markNodesUsed(roots)
   233  	c.markNodesQuiet()
   234  	c.deduplicate()
   235  
   236  	if c.Debug != nil {
   237  		c.printDebugGraph(c.Debug)
   238  	}
   239  
   240  	for _, node := range c.graph.nodes {
   241  		if node.used || node.quiet {
   242  			continue
   243  		}
   244  		obj, ok := node.obj.(types.Object)
   245  		if !ok {
   246  			continue
   247  		}
   248  		found := false
   249  		if !false {
   250  			for _, pkg := range prog.InitialPackages {
   251  				if pkg.Types == obj.Pkg() {
   252  					found = true
   253  					break
   254  				}
   255  			}
   256  		}
   257  		if !found {
   258  			continue
   259  		}
   260  
   261  		pos := c.prog.Fset().Position(obj.Pos())
   262  		if pos.Filename == "" || filepath.Base(pos.Filename) == "C" {
   263  			continue
   264  		}
   265  
   266  		unused = append(unused, Unused{Obj: obj, Position: pos})
   267  	}
   268  	return unused
   269  }
   270  
   271  // isNoCopyType reports whether a type represents the NoCopy sentinel
   272  // type. The NoCopy type is a named struct with no fields and exactly
   273  // one method `func Lock()` that is empty.
   274  //
   275  // FIXME(dh): currently we're not checking that the function body is
   276  // empty.
   277  func isNoCopyType(typ types.Type) bool {
   278  	st, ok := typ.Underlying().(*types.Struct)
   279  	if !ok {
   280  		return false
   281  	}
   282  	if st.NumFields() != 0 {
   283  		return false
   284  	}
   285  
   286  	named, ok := typ.(*types.Named)
   287  	if !ok {
   288  		return false
   289  	}
   290  	if named.NumMethods() != 1 {
   291  		return false
   292  	}
   293  	meth := named.Method(0)
   294  	if meth.Name() != "Lock" {
   295  		return false
   296  	}
   297  	sig := meth.Type().(*types.Signature)
   298  	if sig.Params().Len() != 0 || sig.Results().Len() != 0 {
   299  		return false
   300  	}
   301  	return true
   302  }
   303  
   304  func (c *Checker) useNoCopyFields(typ types.Type) {
   305  	if st, ok := typ.Underlying().(*types.Struct); ok {
   306  		n := st.NumFields()
   307  		for i := 0; i < n; i++ {
   308  			field := st.Field(i)
   309  			if isNoCopyType(field.Type()) {
   310  				c.graph.markUsedBy(field, typ)
   311  				c.graph.markUsedBy(field.Type().(*types.Named).Method(0), field.Type())
   312  			}
   313  		}
   314  	}
   315  }
   316  
   317  func (c *Checker) useExportedFields(typ types.Type, by types.Type) bool {
   318  	any := false
   319  	if st, ok := typ.Underlying().(*types.Struct); ok {
   320  		n := st.NumFields()
   321  		for i := 0; i < n; i++ {
   322  			field := st.Field(i)
   323  			if field.Anonymous() {
   324  				if c.useExportedFields(field.Type(), typ) {
   325  					c.graph.markUsedBy(field, typ)
   326  				}
   327  			}
   328  			if field.Exported() {
   329  				c.graph.markUsedBy(field, by)
   330  				any = true
   331  			}
   332  		}
   333  	}
   334  	return any
   335  }
   336  
   337  func (c *Checker) useExportedMethods(typ types.Type) {
   338  	named, ok := typ.(*types.Named)
   339  	if !ok {
   340  		return
   341  	}
   342  	ms := typeutil.IntuitiveMethodSet(named, &c.msCache)
   343  	for i := 0; i < len(ms); i++ {
   344  		meth := ms[i].Obj()
   345  		if meth.Exported() {
   346  			c.graph.markUsedBy(meth, typ)
   347  		}
   348  	}
   349  
   350  	st, ok := named.Underlying().(*types.Struct)
   351  	if !ok {
   352  		return
   353  	}
   354  	n := st.NumFields()
   355  	for i := 0; i < n; i++ {
   356  		field := st.Field(i)
   357  		if !field.Anonymous() {
   358  			continue
   359  		}
   360  		ms := typeutil.IntuitiveMethodSet(field.Type(), &c.msCache)
   361  		for j := 0; j < len(ms); j++ {
   362  			if ms[j].Obj().Exported() {
   363  				c.graph.markUsedBy(field, typ)
   364  				break
   365  			}
   366  		}
   367  	}
   368  }
   369  
   370  func (c *Checker) processDefs(pkg *lint.Pkg) {
   371  	for _, obj := range pkg.TypesInfo.Defs {
   372  		if obj == nil {
   373  			continue
   374  		}
   375  		c.graph.getNode(obj)
   376  
   377  		if obj, ok := obj.(*types.TypeName); ok {
   378  			c.graph.markUsedBy(obj.Type().Underlying(), obj.Type())
   379  			c.graph.markUsedBy(obj.Type(), obj) // TODO is this needed?
   380  			c.graph.markUsedBy(obj, obj.Type())
   381  
   382  			// We mark all exported fields as used. For normal
   383  			// operation, we have to. The user may use these fields
   384  			// without us knowing.
   385  			//
   386  			// TODO(dh): In whole-program mode, however, we mark them
   387  			// as used because of reflection (such as JSON
   388  			// marshaling). Strictly speaking, we would only need to
   389  			// mark them used if an instance of the type was
   390  			// accessible via an interface value.
   391  			if !c.WholeProgram || c.ConsiderReflection {
   392  				c.useExportedFields(obj.Type(), obj.Type())
   393  			}
   394  
   395  			// TODO(dh): Traditionally we have not marked all exported
   396  			// methods as exported, even though they're strictly
   397  			// speaking accessible through reflection. We've done that
   398  			// because using methods just via reflection is rare, and
   399  			// not worth the false negatives. With the new -reflect
   400  			// flag, however, we should reconsider that choice.
   401  			if !c.WholeProgram {
   402  				c.useExportedMethods(obj.Type())
   403  			}
   404  		}
   405  
   406  		switch obj := obj.(type) {
   407  		case *types.Var, *types.Const, *types.Func, *types.TypeName:
   408  			if obj.Exported() {
   409  				// Exported variables and constants use their types,
   410  				// even if there's no expression using them in the
   411  				// checked program.
   412  				//
   413  				// Also operates on funcs and type names, but that's
   414  				// irrelevant/redundant.
   415  				c.graph.markUsedBy(obj.Type(), obj)
   416  			}
   417  			if obj.Name() == "_" {
   418  				node := c.graph.getNode(obj)
   419  				node.quiet = true
   420  				scope := c.topmostScope(pkg.Types.Scope().Innermost(obj.Pos()), pkg.Types)
   421  				if scope == pkg.Types.Scope() {
   422  					c.graph.roots = append(c.graph.roots, node)
   423  				} else {
   424  					c.graph.markUsedBy(obj, scope)
   425  				}
   426  			} else {
   427  				// Variables declared in functions are used. This is
   428  				// done so that arguments and return parameters are
   429  				// always marked as used.
   430  				if _, ok := obj.(*types.Var); ok {
   431  					if obj.Parent() != obj.Pkg().Scope() && obj.Parent() != nil {
   432  						c.graph.markUsedBy(obj, c.topmostScope(obj.Parent(), obj.Pkg()))
   433  						c.graph.markUsedBy(obj.Type(), obj)
   434  					}
   435  				}
   436  			}
   437  		}
   438  
   439  		if fn, ok := obj.(*types.Func); ok {
   440  			// A function uses its signature
   441  			c.graph.markUsedBy(fn, fn.Type())
   442  
   443  			// A function uses its return types
   444  			sig := fn.Type().(*types.Signature)
   445  			res := sig.Results()
   446  			n := res.Len()
   447  			for i := 0; i < n; i++ {
   448  				c.graph.markUsedBy(res.At(i).Type(), fn)
   449  			}
   450  		}
   451  
   452  		if obj, ok := obj.(interface {
   453  			Scope() *types.Scope
   454  			Pkg() *types.Package
   455  		}); ok {
   456  			scope := obj.Scope()
   457  			c.graph.markUsedBy(c.topmostScope(scope, obj.Pkg()), obj)
   458  		}
   459  
   460  		if c.isRoot(obj) {
   461  			node := c.graph.getNode(obj)
   462  			c.graph.roots = append(c.graph.roots, node)
   463  			if obj, ok := obj.(*types.PkgName); ok {
   464  				scope := obj.Pkg().Scope()
   465  				c.graph.markUsedBy(scope, obj)
   466  			}
   467  		}
   468  	}
   469  }
   470  
   471  func (c *Checker) processUses(pkg *lint.Pkg) {
   472  	for ident, usedObj := range pkg.TypesInfo.Uses {
   473  		if _, ok := usedObj.(*types.PkgName); ok {
   474  			continue
   475  		}
   476  		pos := ident.Pos()
   477  		scope := pkg.Types.Scope().Innermost(pos)
   478  		scope = c.topmostScope(scope, pkg.Types)
   479  		if scope != pkg.Types.Scope() {
   480  			c.graph.markUsedBy(usedObj, scope)
   481  		}
   482  
   483  		switch usedObj.(type) {
   484  		case *types.Var, *types.Const:
   485  			c.graph.markUsedBy(usedObj.Type(), usedObj)
   486  		}
   487  	}
   488  }
   489  
   490  func (c *Checker) findExportedInterfaces() {
   491  	c.interfaces = []*types.Interface{types.Universe.Lookup("error").Type().(*types.Named).Underlying().(*types.Interface)}
   492  	var pkgs []*packages.Package
   493  	if c.WholeProgram {
   494  		pkgs = append(pkgs, c.prog.AllPackages...)
   495  	} else {
   496  		for _, pkg := range c.prog.InitialPackages {
   497  			pkgs = append(pkgs, pkg.Package)
   498  		}
   499  	}
   500  
   501  	for _, pkg := range pkgs {
   502  		for _, tv := range pkg.TypesInfo.Types {
   503  			iface, ok := tv.Type.(*types.Interface)
   504  			if !ok {
   505  				continue
   506  			}
   507  			if iface.NumMethods() == 0 {
   508  				continue
   509  			}
   510  			c.interfaces = append(c.interfaces, iface)
   511  		}
   512  	}
   513  }
   514  
   515  func (c *Checker) processTypes(pkg *lint.Pkg) {
   516  	named := map[*types.Named]*types.Pointer{}
   517  	var interfaces []*types.Interface
   518  	for _, tv := range pkg.TypesInfo.Types {
   519  		if typ, ok := tv.Type.(interface {
   520  			Elem() types.Type
   521  		}); ok {
   522  			c.graph.markUsedBy(typ.Elem(), typ)
   523  		}
   524  
   525  		switch obj := tv.Type.(type) {
   526  		case *types.Named:
   527  			named[obj] = types.NewPointer(obj)
   528  			c.graph.markUsedBy(obj, obj.Underlying())
   529  			c.graph.markUsedBy(obj.Underlying(), obj)
   530  		case *types.Interface:
   531  			if obj.NumMethods() > 0 {
   532  				interfaces = append(interfaces, obj)
   533  			}
   534  		case *types.Struct:
   535  			c.useNoCopyFields(obj)
   536  			if pkg.Types.Name() != "main" && !c.WholeProgram {
   537  				c.useExportedFields(obj, obj)
   538  			}
   539  		}
   540  	}
   541  
   542  	// Pretend that all types are meant to implement as many
   543  	// interfaces as possible.
   544  	//
   545  	// TODO(dh): For normal operations, that's the best we can do, as
   546  	// we have no idea what external users will do with our types. In
   547  	// whole-program mode, we could be more precise, in two ways:
   548  	// 1) Only consider interfaces if a type has been assigned to one
   549  	// 2) Use SSA and flow analysis and determine the exact set of
   550  	// interfaces that is relevant.
   551  	fn := func(iface *types.Interface) {
   552  		for i := 0; i < iface.NumEmbeddeds(); i++ {
   553  			c.graph.markUsedBy(iface.Embedded(i), iface)
   554  		}
   555  		for obj, objPtr := range named {
   556  			if !types.Implements(obj, iface) && !types.Implements(objPtr, iface) {
   557  				continue
   558  			}
   559  			ifaceMethods := make(map[string]struct{}, iface.NumMethods())
   560  			n := iface.NumMethods()
   561  			for i := 0; i < n; i++ {
   562  				meth := iface.Method(i)
   563  				ifaceMethods[meth.Name()] = struct{}{}
   564  			}
   565  			for _, obj := range []types.Type{obj, objPtr} {
   566  				ms := c.msCache.MethodSet(obj)
   567  				n := ms.Len()
   568  				for i := 0; i < n; i++ {
   569  					sel := ms.At(i)
   570  					meth := sel.Obj().(*types.Func)
   571  					_, found := ifaceMethods[meth.Name()]
   572  					if !found {
   573  						continue
   574  					}
   575  					c.graph.markUsedBy(meth.Type().(*types.Signature).Recv().Type(), obj) // embedded receiver
   576  					if len(sel.Index()) > 1 {
   577  						f := getField(obj, sel.Index()[0])
   578  						c.graph.markUsedBy(f, obj) // embedded receiver
   579  					}
   580  					c.graph.markUsedBy(meth, obj)
   581  				}
   582  			}
   583  		}
   584  	}
   585  
   586  	for _, iface := range interfaces {
   587  		fn(iface)
   588  	}
   589  	for _, iface := range c.interfaces {
   590  		fn(iface)
   591  	}
   592  }
   593  
   594  func (c *Checker) processSelections(pkg *lint.Pkg) {
   595  	fn := func(expr *ast.SelectorExpr, sel *types.Selection, offset int) {
   596  		scope := pkg.Types.Scope().Innermost(expr.Pos())
   597  		c.graph.markUsedBy(expr.X, c.topmostScope(scope, pkg.Types))
   598  		c.graph.markUsedBy(sel.Obj(), expr.X)
   599  		if len(sel.Index()) > 1 {
   600  			typ := sel.Recv()
   601  			indices := sel.Index()
   602  			for _, idx := range indices[:len(indices)-offset] {
   603  				obj := getField(typ, idx)
   604  				typ = obj.Type()
   605  				c.graph.markUsedBy(obj, expr.X)
   606  			}
   607  		}
   608  	}
   609  
   610  	for expr, sel := range pkg.TypesInfo.Selections {
   611  		switch sel.Kind() {
   612  		case types.FieldVal:
   613  			fn(expr, sel, 0)
   614  		case types.MethodVal:
   615  			fn(expr, sel, 1)
   616  		}
   617  	}
   618  }
   619  
   620  func dereferenceType(typ types.Type) types.Type {
   621  	if typ, ok := typ.(*types.Pointer); ok {
   622  		return typ.Elem()
   623  	}
   624  	return typ
   625  }
   626  
   627  // processConversion marks fields as used if they're part of a type conversion.
   628  func (c *Checker) processConversion(pkg *lint.Pkg, node ast.Node) {
   629  	if node, ok := node.(*ast.CallExpr); ok {
   630  		callTyp := pkg.TypesInfo.TypeOf(node.Fun)
   631  		var typDst *types.Struct
   632  		var ok bool
   633  		switch typ := callTyp.(type) {
   634  		case *types.Named:
   635  			typDst, ok = typ.Underlying().(*types.Struct)
   636  		case *types.Pointer:
   637  			typDst, ok = typ.Elem().Underlying().(*types.Struct)
   638  		default:
   639  			return
   640  		}
   641  		if !ok {
   642  			return
   643  		}
   644  
   645  		if typ, ok := pkg.TypesInfo.TypeOf(node.Args[0]).(*types.Basic); ok && typ.Kind() == types.UnsafePointer {
   646  			// This is an unsafe conversion. Assume that all the
   647  			// fields are relevant (they are, because of memory
   648  			// layout)
   649  			n := typDst.NumFields()
   650  			for i := 0; i < n; i++ {
   651  				c.graph.markUsedBy(typDst.Field(i), typDst)
   652  			}
   653  			return
   654  		}
   655  
   656  		typSrc, ok := dereferenceType(pkg.TypesInfo.TypeOf(node.Args[0])).Underlying().(*types.Struct)
   657  		if !ok {
   658  			return
   659  		}
   660  
   661  		// When we convert from type t1 to t2, were t1 and t2 are
   662  		// structs, all fields are relevant, as otherwise the
   663  		// conversion would fail.
   664  		//
   665  		// We mark t2's fields as used by t1's fields, and vice
   666  		// versa. That way, if no code actually refers to a field
   667  		// in either type, it's still correctly marked as unused.
   668  		// If a field is used in either struct, it's implicitly
   669  		// relevant in the other one, too.
   670  		//
   671  		// It works in a similar way for conversions between types
   672  		// of two packages, only that the extra information in the
   673  		// graph is redundant unless we're in whole program mode.
   674  		n := typDst.NumFields()
   675  		for i := 0; i < n; i++ {
   676  			fDst := typDst.Field(i)
   677  			fSrc := typSrc.Field(i)
   678  			c.graph.markUsedBy(fDst, fSrc)
   679  			c.graph.markUsedBy(fSrc, fDst)
   680  		}
   681  	}
   682  }
   683  
   684  // processCompositeLiteral marks fields as used if the struct is used
   685  // in a composite literal.
   686  func (c *Checker) processCompositeLiteral(pkg *lint.Pkg, node ast.Node) {
   687  	// XXX how does this actually work? wouldn't it match t{}?
   688  	if node, ok := node.(*ast.CompositeLit); ok {
   689  		typ := pkg.TypesInfo.TypeOf(node)
   690  		if _, ok := typ.(*types.Named); ok {
   691  			typ = typ.Underlying()
   692  		}
   693  		if _, ok := typ.(*types.Struct); !ok {
   694  			return
   695  		}
   696  
   697  		if isBasicStruct(node.Elts) {
   698  			c.markFields(typ)
   699  		}
   700  	}
   701  }
   702  
   703  // processCgoExported marks functions as used if they're being
   704  // exported to cgo.
   705  func (c *Checker) processCgoExported(pkg *lint.Pkg, node ast.Node) {
   706  	if node, ok := node.(*ast.FuncDecl); ok {
   707  		if node.Doc == nil {
   708  			return
   709  		}
   710  		for _, cmt := range node.Doc.List {
   711  			if !strings.HasPrefix(cmt.Text, "//go:cgo_export_") {
   712  				return
   713  			}
   714  			obj := pkg.TypesInfo.ObjectOf(node.Name)
   715  			c.graph.roots = append(c.graph.roots, c.graph.getNode(obj))
   716  		}
   717  	}
   718  }
   719  
   720  func (c *Checker) processVariableDeclaration(pkg *lint.Pkg, node ast.Node) {
   721  	if decl, ok := node.(*ast.GenDecl); ok {
   722  		for _, spec := range decl.Specs {
   723  			spec, ok := spec.(*ast.ValueSpec)
   724  			if !ok {
   725  				continue
   726  			}
   727  			for i, name := range spec.Names {
   728  				if i >= len(spec.Values) {
   729  					break
   730  				}
   731  				value := spec.Values[i]
   732  				fn := func(node ast.Node) bool {
   733  					if node3, ok := node.(*ast.Ident); ok {
   734  						obj := pkg.TypesInfo.ObjectOf(node3)
   735  						if _, ok := obj.(*types.PkgName); ok {
   736  							return true
   737  						}
   738  						c.graph.markUsedBy(obj, pkg.TypesInfo.ObjectOf(name))
   739  					}
   740  					return true
   741  				}
   742  				ast.Inspect(value, fn)
   743  			}
   744  		}
   745  	}
   746  }
   747  
   748  func (c *Checker) processArrayConstants(pkg *lint.Pkg, node ast.Node) {
   749  	if decl, ok := node.(*ast.ArrayType); ok {
   750  		ident, ok := decl.Len.(*ast.Ident)
   751  		if !ok {
   752  			return
   753  		}
   754  		c.graph.markUsedBy(pkg.TypesInfo.ObjectOf(ident), pkg.TypesInfo.TypeOf(decl))
   755  	}
   756  }
   757  
   758  func (c *Checker) processKnownReflectMethodCallers(pkg *lint.Pkg, node ast.Node) {
   759  	call, ok := node.(*ast.CallExpr)
   760  	if !ok {
   761  		return
   762  	}
   763  	sel, ok := call.Fun.(*ast.SelectorExpr)
   764  	if !ok {
   765  		return
   766  	}
   767  	if !IsType(pkg.TypesInfo.TypeOf(sel.X), "*net/rpc.Server") {
   768  		x, ok := sel.X.(*ast.Ident)
   769  		if !ok {
   770  			return
   771  		}
   772  		pkgname, ok := pkg.TypesInfo.ObjectOf(x).(*types.PkgName)
   773  		if !ok {
   774  			return
   775  		}
   776  		if pkgname.Imported().Path() != "net/rpc" {
   777  			return
   778  		}
   779  	}
   780  
   781  	var arg ast.Expr
   782  	switch sel.Sel.Name {
   783  	case "Register":
   784  		if len(call.Args) != 1 {
   785  			return
   786  		}
   787  		arg = call.Args[0]
   788  	case "RegisterName":
   789  		if len(call.Args) != 2 {
   790  			return
   791  		}
   792  		arg = call.Args[1]
   793  	}
   794  	typ := pkg.TypesInfo.TypeOf(arg)
   795  	ms := types.NewMethodSet(typ)
   796  	for i := 0; i < ms.Len(); i++ {
   797  		c.graph.markUsedBy(ms.At(i).Obj(), typ)
   798  	}
   799  }
   800  
   801  func (c *Checker) processAST(pkg *lint.Pkg) {
   802  	fn := func(node ast.Node) bool {
   803  		c.processConversion(pkg, node)
   804  		c.processKnownReflectMethodCallers(pkg, node)
   805  		c.processCompositeLiteral(pkg, node)
   806  		c.processCgoExported(pkg, node)
   807  		c.processVariableDeclaration(pkg, node)
   808  		c.processArrayConstants(pkg, node)
   809  		return true
   810  	}
   811  	for _, file := range pkg.Syntax {
   812  		ast.Inspect(file, fn)
   813  	}
   814  }
   815  
   816  func isBasicStruct(elts []ast.Expr) bool {
   817  	for _, elt := range elts {
   818  		if _, ok := elt.(*ast.KeyValueExpr); !ok {
   819  			return true
   820  		}
   821  	}
   822  	return false
   823  }
   824  
   825  func isPkgScope(obj types.Object) bool {
   826  	return obj.Parent() == obj.Pkg().Scope()
   827  }
   828  
   829  func isMain(obj types.Object) bool {
   830  	if obj.Pkg().Name() != "main" {
   831  		return false
   832  	}
   833  	if obj.Name() != "main" {
   834  		return false
   835  	}
   836  	if !isPkgScope(obj) {
   837  		return false
   838  	}
   839  	if !isFunction(obj) {
   840  		return false
   841  	}
   842  	if isMethod(obj) {
   843  		return false
   844  	}
   845  	return true
   846  }
   847  
   848  func isFunction(obj types.Object) bool {
   849  	_, ok := obj.(*types.Func)
   850  	return ok
   851  }
   852  
   853  func isMethod(obj types.Object) bool {
   854  	if !isFunction(obj) {
   855  		return false
   856  	}
   857  	return obj.(*types.Func).Type().(*types.Signature).Recv() != nil
   858  }
   859  
   860  func isVariable(obj types.Object) bool {
   861  	_, ok := obj.(*types.Var)
   862  	return ok
   863  }
   864  
   865  func isConstant(obj types.Object) bool {
   866  	_, ok := obj.(*types.Const)
   867  	return ok
   868  }
   869  
   870  func isType(obj types.Object) bool {
   871  	_, ok := obj.(*types.TypeName)
   872  	return ok
   873  }
   874  
   875  func isField(obj types.Object) bool {
   876  	if obj, ok := obj.(*types.Var); ok && obj.IsField() {
   877  		return true
   878  	}
   879  	return false
   880  }
   881  
   882  func (c *Checker) checkFlags(v interface{}) bool {
   883  	obj, ok := v.(types.Object)
   884  	if !ok {
   885  		return false
   886  	}
   887  	if isFunction(obj) && !c.checkFunctions() {
   888  		return false
   889  	}
   890  	if isVariable(obj) && !c.checkVariables() {
   891  		return false
   892  	}
   893  	if isConstant(obj) && !c.checkConstants() {
   894  		return false
   895  	}
   896  	if isType(obj) && !c.checkTypes() {
   897  		return false
   898  	}
   899  	if isField(obj) && !c.checkFields() {
   900  		return false
   901  	}
   902  	return true
   903  }
   904  
   905  func (c *Checker) isRoot(obj types.Object) bool {
   906  	// - in local mode, main, init, tests, and non-test, non-main exported are roots
   907  	// - in global mode (not yet implemented), main, init and tests are roots
   908  
   909  	if _, ok := obj.(*types.PkgName); ok {
   910  		return true
   911  	}
   912  
   913  	if isMain(obj) || (isFunction(obj) && !isMethod(obj) && obj.Name() == "init") {
   914  		return true
   915  	}
   916  	if obj.Exported() {
   917  		f := c.prog.Fset().Position(obj.Pos()).Filename
   918  		if strings.HasSuffix(f, "_test.go") {
   919  			return strings.HasPrefix(obj.Name(), "Test") ||
   920  				strings.HasPrefix(obj.Name(), "Benchmark") ||
   921  				strings.HasPrefix(obj.Name(), "Example")
   922  		}
   923  
   924  		// Package-level are used, except in package main
   925  		if isPkgScope(obj) && obj.Pkg().Name() != "main" && !c.WholeProgram {
   926  			return true
   927  		}
   928  	}
   929  	return false
   930  }
   931  
   932  func markNodesUsed(nodes map[*graphNode]struct{}) {
   933  	for node := range nodes {
   934  		wasUsed := node.used
   935  		node.used = true
   936  		if !wasUsed {
   937  			markNodesUsed(node.uses)
   938  		}
   939  	}
   940  }
   941  
   942  // deduplicate merges objects based on their positions. This is done
   943  // to work around packages existing multiple times in go/packages.
   944  func (c *Checker) deduplicate() {
   945  	m := map[token.Position]struct{ used, quiet bool }{}
   946  	for _, node := range c.graph.nodes {
   947  		obj, ok := node.obj.(types.Object)
   948  		if !ok {
   949  			continue
   950  		}
   951  		pos := c.prog.Fset().Position(obj.Pos())
   952  		m[pos] = struct{ used, quiet bool }{
   953  			m[pos].used || node.used,
   954  			m[pos].quiet || node.quiet,
   955  		}
   956  	}
   957  
   958  	for _, node := range c.graph.nodes {
   959  		obj, ok := node.obj.(types.Object)
   960  		if !ok {
   961  			continue
   962  		}
   963  		pos := c.prog.Fset().Position(obj.Pos())
   964  		node.used = m[pos].used
   965  		node.quiet = m[pos].quiet
   966  	}
   967  }
   968  
   969  func (c *Checker) markNodesQuiet() {
   970  	for _, node := range c.graph.nodes {
   971  		if node.used {
   972  			continue
   973  		}
   974  		if obj, ok := node.obj.(types.Object); ok && !c.checkFlags(obj) {
   975  			node.quiet = true
   976  			continue
   977  		}
   978  		c.markObjQuiet(node.obj)
   979  	}
   980  }
   981  
   982  func (c *Checker) markObjQuiet(obj interface{}) {
   983  	switch obj := obj.(type) {
   984  	case *types.Named:
   985  		n := obj.NumMethods()
   986  		for i := 0; i < n; i++ {
   987  			meth := obj.Method(i)
   988  			node := c.graph.getNode(meth)
   989  			node.quiet = true
   990  			c.markObjQuiet(meth.Scope())
   991  		}
   992  	case *types.Struct:
   993  		n := obj.NumFields()
   994  		for i := 0; i < n; i++ {
   995  			field := obj.Field(i)
   996  			c.graph.nodes[field].quiet = true
   997  		}
   998  	case *types.Func:
   999  		c.markObjQuiet(obj.Scope())
  1000  	case *types.Scope:
  1001  		if obj == nil {
  1002  			return
  1003  		}
  1004  		if obj.Parent() == types.Universe {
  1005  			return
  1006  		}
  1007  		for _, name := range obj.Names() {
  1008  			v := obj.Lookup(name)
  1009  			if n, ok := c.graph.nodes[v]; ok {
  1010  				n.quiet = true
  1011  			}
  1012  		}
  1013  		n := obj.NumChildren()
  1014  		for i := 0; i < n; i++ {
  1015  			c.markObjQuiet(obj.Child(i))
  1016  		}
  1017  	}
  1018  }
  1019  
  1020  func getField(typ types.Type, idx int) *types.Var {
  1021  	switch obj := typ.(type) {
  1022  	case *types.Pointer:
  1023  		return getField(obj.Elem(), idx)
  1024  	case *types.Named:
  1025  		switch v := obj.Underlying().(type) {
  1026  		case *types.Struct:
  1027  			return v.Field(idx)
  1028  		case *types.Pointer:
  1029  			return getField(v.Elem(), idx)
  1030  		default:
  1031  			panic(fmt.Sprintf("unexpected type %s", typ))
  1032  		}
  1033  	case *types.Struct:
  1034  		return obj.Field(idx)
  1035  	}
  1036  	return nil
  1037  }
  1038  
  1039  func (c *Checker) topmostScope(scope *types.Scope, pkg *types.Package) (ret *types.Scope) {
  1040  	if top, ok := c.topmostCache[scope]; ok {
  1041  		return top
  1042  	}
  1043  	defer func() {
  1044  		c.topmostCache[scope] = ret
  1045  	}()
  1046  	if scope == pkg.Scope() {
  1047  		return scope
  1048  	}
  1049  	if scope.Parent().Parent() == pkg.Scope() {
  1050  		return scope
  1051  	}
  1052  	return c.topmostScope(scope.Parent(), pkg)
  1053  }
  1054  
  1055  func (c *Checker) printDebugGraph(w io.Writer) {
  1056  	fmt.Fprintln(w, "digraph {")
  1057  	fmt.Fprintln(w, "n0 [label = roots]")
  1058  	for _, node := range c.graph.nodes {
  1059  		s := fmt.Sprintf("%s (%T)", node.obj, node.obj)
  1060  		s = strings.Replace(s, "\n", "", -1)
  1061  		s = strings.Replace(s, `"`, "", -1)
  1062  		fmt.Fprintf(w, `n%d [label = %q]`, node.n, s)
  1063  		color := "black"
  1064  		switch {
  1065  		case node.used:
  1066  			color = "green"
  1067  		case node.quiet:
  1068  			color = "orange"
  1069  		case !c.checkFlags(node.obj):
  1070  			color = "purple"
  1071  		default:
  1072  			color = "red"
  1073  		}
  1074  		fmt.Fprintf(w, "[color = %s]", color)
  1075  		fmt.Fprintln(w)
  1076  	}
  1077  
  1078  	for _, node1 := range c.graph.nodes {
  1079  		for node2 := range node1.uses {
  1080  			fmt.Fprintf(w, "n%d -> n%d\n", node1.n, node2.n)
  1081  		}
  1082  	}
  1083  	for _, root := range c.graph.roots {
  1084  		fmt.Fprintf(w, "n0 -> n%d\n", root.n)
  1085  	}
  1086  	fmt.Fprintln(w, "}")
  1087  }