12 "honnef.co/go/tools/analysis/code"
13 "honnef.co/go/tools/analysis/facts"
14 "honnef.co/go/tools/analysis/lint"
15 "honnef.co/go/tools/analysis/report"
16 "honnef.co/go/tools/go/ast/astutil"
17 "honnef.co/go/tools/go/ir"
18 "honnef.co/go/tools/go/types/typeutil"
19 "honnef.co/go/tools/internal/passes/buildir"
21 "golang.org/x/tools/go/analysis"
26 // The graph we construct omits nodes along a path that do not
27 // contribute any new information to the solution. For example, the
28 // full graph for a function with a receiver would be Func ->
29 // Signature -> Var -> Type. However, since signatures cannot be
30 // unused, and receivers are always considered used, we can compact
31 // the graph down to Func -> Type. This makes the graph smaller, but
34 // TODO(dh): conversions between structs mark fields as used, but the
35 // conversion itself isn't part of that subgraph. even if the function
36 // containing the conversion is unused, the fields will be marked as
39 // TODO(dh): we cannot observe function calls in assembly files.
44 - (1.1) exported named types
45 - (1.2) exported functions
46 - (1.3) exported variables
47 - (1.4) exported constants
48 - (1.5) init functions
49 - (1.6) functions exported to cgo
50 - (1.7) the main function iff in the main package
51 - (1.8) symbols linked via go:linkname
54 - (2.1) exported methods
55 - (2.2) the type they're based on
56 - (2.3) all their aliases. we can't easily track uses of aliases
57 because go/types turns them into uses of the aliased types. assume
58 that if a type is used, so are all of its aliases.
59 - (2.4) the pointer type. this aids with eagerly implementing
60 interfaces. if a method that implements an interface is defined on
61 a pointer receiver, and the pointer type is never used, but the
62 named type is, then we still want to mark the method as used.
64 - variables and constants use:
68 - (4.1) all their arguments, return parameters and receivers
69 - (4.2) anonymous functions defined beneath them
70 - (4.3) closures and bound methods.
71 this implements a simplified model where a function is used merely by being referenced, even if it is never called.
72 that way we don't have to keep track of closures escaping functions.
73 - (4.4) functions they return. we assume that someone else will call the returned function
74 - (4.5) functions/interface methods they call
75 - types they instantiate or convert to
76 - (4.7) fields they access
77 - (4.8) types of all instructions
78 - (4.9) package-level variables they assign to iff in tests (sinks for benchmarks)
81 - (5.1) when converting between two equivalent structs, the fields in
82 either struct use each other. the fields are relevant for the
83 conversion, but only if the fields are also accessed outside the
85 - (5.2) when converting to or from unsafe.Pointer, mark all fields as used.
88 - (6.1) fields of type NoCopy sentinel
89 - (6.2) exported fields
90 - (6.3) embedded fields that help implement interfaces (either fully implements it, or contributes required methods) (recursively)
91 - (6.4) embedded fields that have exported methods (recursively)
92 - (6.5) embedded structs that have exported fields (recursively)
94 - (7.1) field accesses use fields
95 - (7.2) fields use their types
97 - (8.0) How we handle interfaces:
98 - (8.1) We do not technically care about interfaces that only consist of
99 exported methods. Exported methods on concrete types are always
101 - Any concrete type implements all known interfaces. Even if it isn't
102 assigned to any interfaces in our code, the user may receive a value
103 of the type and expect to pass it back to us through an interface.
105 Concrete types use their methods that implement interfaces. If the
106 type is used, it uses those methods. Otherwise, it doesn't. This
107 way, types aren't incorrectly marked reachable through the edge
110 - (8.3) All interface methods are marked as used, even if they never get
111 called. This is to accommodate sum types (unexported interface
112 method that must exist but never gets called.)
114 - (8.4) All embedded interfaces are marked as used. This is an
115 extension of 8.3, but we have to explicitly track embedded
116 interfaces because in a chain C->B->A, B wouldn't be marked as
117 used by 8.3 just because it contributes A's methods to C.
120 - thunks and other generated wrappers call the real function
121 - (9.2) variables use their types
122 - (9.3) types use their underlying and element types
123 - (9.4) conversions use the type they convert to
124 - (9.5) instructions use their operands
125 - (9.6) instructions use their operands' types
126 - (9.7) variable _reads_ use variables, writes do not, except in tests
127 - (9.8) runtime functions that may be called from user code via the compiler
131 (10.1) if one constant out of a block of constants is used, mark all
132 of them used. a lot of the time, unused constants exist for the sake
133 of completeness. See also
134 https://github.com/dominikh/go-tools/issues/365
137 - (11.1) anonymous struct types use all their fields. we cannot
138 deduplicate struct types, as that leads to order-dependent
139 reportings. we can't not deduplicate struct types while still
140 tracking fields, because then each instance of the unnamed type in
141 the data flow chain will get its own fields, causing false
142 positives. Thus, we only accurately track fields of named struct
143 types, and assume that unnamed struct types use all their fields.
147 func assert(b bool) {
149 panic("failed assertion")
153 // /usr/lib/go/src/runtime/proc.go:433:6: func badmorestackg0 is unused (U1000)
155 // Functions defined in the Go runtime that may be called through
156 // compiler magic or via assembly.
157 var runtimeFuncs = map[string]bool{
158 // The first part of the list is copied from
159 // cmd/compile/internal/gc/builtin.go, var runtimeDecls
164 "panicmakeslicelen": true,
169 "goschedguarded": true,
175 "printcomplex": true,
177 "printpointer": true,
185 "concatstring2": true,
186 "concatstring3": true,
187 "concatstring4": true,
188 "concatstring5": true,
189 "concatstrings": true,
192 "slicebytetostring": true,
193 "slicebytetostringtmp": true,
194 "slicerunetostring": true,
195 "stringtoslicebyte": true,
196 "stringtoslicerune": true,
198 "slicestringcopy": true,
208 "convT2Enoptr": true,
210 "convT2Inoptr": true,
215 "panicdottypeE": true,
216 "panicdottypeI": true,
217 "panicnildottype": true,
223 "makemap_small": true,
225 "mapaccess1_fast32": true,
226 "mapaccess1_fast64": true,
227 "mapaccess1_faststr": true,
228 "mapaccess1_fat": true,
230 "mapaccess2_fast32": true,
231 "mapaccess2_fast64": true,
232 "mapaccess2_faststr": true,
233 "mapaccess2_fat": true,
235 "mapassign_fast32": true,
236 "mapassign_fast32ptr": true,
237 "mapassign_fast64": true,
238 "mapassign_fast64ptr": true,
239 "mapassign_faststr": true,
242 "mapdelete_fast32": true,
243 "mapdelete_fast64": true,
244 "mapdelete_faststr": true,
253 "writeBarrier": true,
254 "typedmemmove": true,
256 "typedslicecopy": true,
257 "selectnbsend": true,
258 "selectnbrecv": true,
259 "selectnbrecv2": true,
267 "memclrNoHeapPointers": true,
268 "memclrHasPointers": true,
279 "float64toint64": true,
280 "float64touint64": true,
281 "float64touint32": true,
282 "int64tofloat64": true,
283 "uint64tofloat64": true,
284 "uint32tofloat64": true,
285 "complex128div": true,
286 "racefuncenter": true,
287 "racefuncenterfp": true,
288 "racefuncexit": true,
291 "racereadrange": true,
292 "racewriterange": true,
295 "x86HasPOPCNT": true,
297 "arm64HasATOMICS": true,
299 // The second part of the list is extracted from assembly code in
300 // the standard library, with the exception of the runtime package itself
308 "badmorestackg0": true,
309 "badmorestackgsignal": true,
311 "callbackasm1": true,
312 "callCfunction": true,
313 "cgocallback_gofunc": true,
314 "cgocallbackg": true,
317 "debugCallCheck": true,
318 "debugCallWrap": true,
320 "entersyscall": true,
324 "externalthreadhandler": true,
328 "i386_set_ldt": true,
330 "init_thread_tls": true,
336 "nacl_sysinfo": true,
346 "racecallback": true,
347 "reflectcallmove": true,
355 "sigprofNonGo": true,
360 "syscall_chdir": true,
361 "syscall_chroot": true,
362 "syscall_close": true,
363 "syscall_dup2": true,
364 "syscall_execve": true,
365 "syscall_exit": true,
366 "syscall_fcntl": true,
367 "syscall_forkx": true,
368 "syscall_gethostname": true,
369 "syscall_getpid": true,
370 "syscall_ioctl": true,
371 "syscall_pipe": true,
372 "syscall_rawsyscall6": true,
373 "syscall_rawSyscall6": true,
374 "syscall_rawsyscall": true,
375 "syscall_RawSyscall": true,
376 "syscall_rawsysvicall6": true,
377 "syscall_setgid": true,
378 "syscall_setgroups": true,
379 "syscall_setpgid": true,
380 "syscall_setsid": true,
381 "syscall_setuid": true,
382 "syscall_syscall6": true,
383 "syscall_syscall": true,
384 "syscall_Syscall": true,
385 "syscall_sysvicall6": true,
386 "syscall_wait4": true,
387 "syscall_write": true,
399 TypesInfo *types.Info
400 TypesSizes types.Sizes
402 SrcFuncs []*ir.Function
403 Directives []lint.Directive
406 // TODO(dh): should we return a map instead of two slices?
409 Unused []types.Object
412 type SerializedResult struct {
413 Used []SerializedObject
414 Unused []SerializedObject
417 var Analyzer = &analysis.Analyzer{
421 Requires: []*analysis.Analyzer{buildir.Analyzer, facts.Generated, facts.Directives},
422 ResultType: reflect.TypeOf(Result{}),
425 type SerializedObject struct {
427 Position token.Position
428 DisplayPosition token.Position
433 func typString(obj types.Object) string {
434 switch obj := obj.(type) {
444 case *types.TypeName:
451 func Serialize(pass *analysis.Pass, res Result, fset *token.FileSet) SerializedResult {
452 // OPT(dh): there's no point in serializing Used objects that are
453 // always used, such as exported names, blank identifiers, or
454 // anonymous struct fields. Used only exists to overrule Unused of
455 // a different package. If something can never be unused, then its
456 // presence in Used is useless.
458 // I'm not sure if this should happen when serializing, or when
461 out := SerializedResult{
462 Used: make([]SerializedObject, len(res.Used)),
463 Unused: make([]SerializedObject, len(res.Unused)),
465 for i, obj := range res.Used {
466 out.Used[i] = serializeObject(pass, fset, obj)
468 for i, obj := range res.Unused {
469 out.Unused[i] = serializeObject(pass, fset, obj)
474 func serializeObject(pass *analysis.Pass, fset *token.FileSet, obj types.Object) SerializedObject {
476 if sig, ok := obj.Type().(*types.Signature); ok && sig.Recv() != nil {
477 switch sig.Recv().Type().(type) {
478 case *types.Named, *types.Pointer:
479 typ := types.TypeString(sig.Recv().Type(), func(*types.Package) string { return "" })
480 if len(typ) > 0 && typ[0] == '*' {
481 name = fmt.Sprintf("(%s).%s", typ, obj.Name())
482 } else if len(typ) > 0 {
483 name = fmt.Sprintf("%s.%s", typ, obj.Name())
487 return SerializedObject{
489 Position: fset.PositionFor(obj.Pos(), false),
490 DisplayPosition: report.DisplayPosition(fset, obj.Pos()),
491 Kind: typString(obj),
492 InGenerated: code.IsGenerated(pass, obj.Pos()),
496 func debugf(f string, v ...interface{}) {
498 fmt.Fprintf(Debug, f, v...)
502 func run(pass *analysis.Pass) (interface{}, error) {
503 irpkg := pass.ResultOf[buildir.Analyzer].(*buildir.IR)
504 dirs := pass.ResultOf[facts.Directives].([]lint.Directive)
509 TypesInfo: pass.TypesInfo,
510 TypesSizes: pass.TypesSizes,
512 SrcFuncs: irpkg.SrcFuncs,
518 used, unused := results(g)
521 debugNode := func(n *node) {
523 debugf("n%d [label=\"Root\"];\n", n.id)
529 debugf("n%d [label=%q, color=%q];\n", n.id, fmt.Sprintf("(%T) %s", n.obj, n.obj), color)
531 for _, e := range n.used {
532 for i := edgeKind(1); i < 64; i++ {
533 if e.kind.is(1 << i) {
534 debugf("n%d -> n%d [label=%q];\n", n.id, e.node.id, edgeKind(1<<i))
542 for _, v := range g.Nodes {
545 for _, node := range g.TypeNodes {
552 return Result{Used: used, Unused: unused}, nil
555 func results(g *graph) (used, unused []types.Object) {
557 for _, node := range g.TypeNodes {
561 switch obj := node.obj.(type) {
563 for i := 0; i < obj.NumFields(); i++ {
564 if node, ok := g.nodeMaybe(obj.Field(i)); ok {
568 case *types.Interface:
569 for i := 0; i < obj.NumExplicitMethods(); i++ {
570 m := obj.ExplicitMethod(i)
571 if node, ok := g.nodeMaybe(m); ok {
578 // OPT(dh): can we find meaningful initial capacities for the used and unused slices?
580 for _, n := range g.Nodes {
581 if obj, ok := n.obj.(types.Object); ok {
582 switch obj := obj.(type) {
584 // don't report unnamed variables (interface embedding)
585 if obj.Name() == "" && obj.IsField() {
589 if obj.Name() == "_" {
594 if obj.Pkg() != nil {
596 used = append(used, obj)
598 if obj.Pkg() != g.pkg.Pkg {
601 unused = append(unused, obj)
612 seenTypes map[types.Type]struct{}
614 TypeNodes map[types.Type]*node
615 Nodes map[interface{}]*node
619 seenFns map[*ir.Function]struct{}
623 func newGraph() *graph {
625 Nodes: map[interface{}]*node{},
626 seenFns: map[*ir.Function]struct{}{},
627 seenTypes: map[types.Type]struct{}{},
628 TypeNodes: map[types.Type]*node{},
630 g.Root = g.newNode(nil)
634 func (g *graph) color(root *node) {
639 for _, e := range root.used {
644 type constGroup struct {
645 // give the struct a size to get unique pointers
649 func (constGroup) String() string { return "const group" }
660 // OPT(dh): evaluate using a map instead of a slice to avoid
664 // set during final graph walk if node is reachable
669 func (g *graph) nodeMaybe(obj types.Object) (*node, bool) {
670 if node, ok := g.Nodes[obj]; ok {
676 func (g *graph) node(obj interface{}) (n *node, new bool) {
677 switch obj := obj.(type) {
679 if v := g.TypeNodes[obj]; v != nil {
686 // OPT(dh): the types.Object and default cases are identical
687 if node, ok := g.Nodes[obj]; ok {
695 if node, ok := g.Nodes[obj]; ok {
705 func (g *graph) newNode(obj interface{}) *node {
713 func (n *node) use(n2 *node, kind edgeKind) {
715 n.used = append(n.used, edge{node: n2, kind: kind})
718 // isIrrelevant reports whether an object's presence in the graph is
719 // of any relevance. A lot of objects will never have outgoing edges,
720 // nor meaningful incoming ones. Examples are basic types and empty
721 // signatures, among many others.
723 // Dropping these objects should have no effect on correctness, but
724 // may improve performance. It also helps with debugging, as it
725 // greatly reduces the size of the graph.
726 func isIrrelevant(obj interface{}) bool {
727 if obj, ok := obj.(types.Object); ok {
728 switch obj := obj.(type) {
731 // We need to track package fields
734 if obj.Pkg() != nil && obj.Parent() == obj.Pkg().Scope() {
735 // We need to track package-level variables
738 return isIrrelevant(obj.Type())
743 if T, ok := obj.(types.Type); ok {
744 switch T := T.(type) {
746 return isIrrelevant(T.Elem())
748 return isIrrelevant(T.Elem())
752 for i := 0; i < T.Len(); i++ {
753 if !isIrrelevant(T.At(i).Type()) {
758 case *types.Signature:
762 for i := 0; i < T.Params().Len(); i++ {
763 if !isIrrelevant(T.Params().At(i)) {
767 for i := 0; i < T.Results().Len(); i++ {
768 if !isIrrelevant(T.Results().At(i)) {
773 case *types.Interface:
774 return T.NumMethods() == 0 && T.NumEmbeddeds() == 0
776 return isIrrelevant(T.Elem())
778 return isIrrelevant(T.Key()) && isIrrelevant(T.Elem())
780 return T.NumFields() == 0
782 return isIrrelevant(T.Elem())
790 func (g *graph) see(obj interface{}) *node {
791 if isIrrelevant(obj) {
796 // add new node to graph
797 node, _ := g.node(obj)
801 func (g *graph) use(used, by interface{}, kind edgeKind) {
802 if isIrrelevant(used) {
807 if obj, ok := by.(types.Object); ok && obj.Pkg() != nil {
808 if obj.Pkg() != g.pkg.Pkg {
812 usedNode, new := g.node(used)
815 g.Root.use(usedNode, kind)
817 byNode, new := g.node(by)
819 byNode.use(usedNode, kind)
823 func (g *graph) seeAndUse(used, by interface{}, kind edgeKind) *node {
825 g.use(used, by, kind)
829 func (g *graph) entry(pkg *pkg) {
831 scopes := map[*types.Scope]*ir.Function{}
832 for _, fn := range pkg.SrcFuncs {
833 if fn.Object() != nil {
834 scope := fn.Object().(*types.Func).Scope()
839 for _, f := range pkg.Files {
840 for _, cg := range f.Comments {
841 for _, c := range cg.List {
842 if strings.HasPrefix(c.Text, "//go:linkname ") {
843 // FIXME(dh): we're looking at all comments. The
844 // compiler only looks at comments in the
845 // left-most column. The intention probably is to
846 // only look at top-level comments.
848 // (1.8) packages use symbols linked via go:linkname
849 fields := strings.Fields(c.Text)
850 if len(fields) == 3 {
851 if m, ok := pkg.IR.Members[fields[1]]; ok {
853 switch m := m.(type) {
859 panic(fmt.Sprintf("unhandled type: %T", m))
862 g.seeAndUse(obj, nil, edgeLinkname)
870 surroundingFunc := func(obj types.Object) *ir.Function {
871 scope := obj.Parent()
873 if fn := scopes[scope]; fn != nil {
876 scope = scope.Parent()
881 // IR form won't tell us about locally scoped types that aren't
882 // being used. Walk the list of Defs to get all named types.
884 // IR form also won't tell us about constants; use Defs and Uses
885 // to determine which constants exist and which are being used.
886 for _, obj := range pkg.TypesInfo.Defs {
887 switch obj := obj.(type) {
888 case *types.TypeName:
889 // types are being handled by walking the AST
892 fn := surroundingFunc(obj)
893 if fn == nil && obj.Exported() {
894 // (1.4) packages use exported constants
895 g.use(obj, nil, edgeExportedConstant)
897 g.typ(obj.Type(), nil)
898 g.seeAndUse(obj.Type(), obj, edgeType)
902 // Find constants being used inside functions, find sinks in tests
903 for _, fn := range pkg.SrcFuncs {
904 if fn.Object() != nil {
911 ast.Inspect(n, func(n ast.Node) bool {
912 switch n := n.(type) {
914 obj, ok := pkg.TypesInfo.Uses[n]
918 switch obj := obj.(type) {
920 g.seeAndUse(obj, owningObject(fn), edgeUsedConstant)
922 case *ast.AssignStmt:
923 for _, expr := range n.Lhs {
924 ident, ok := expr.(*ast.Ident)
928 obj := pkg.TypesInfo.ObjectOf(ident)
932 path := pkg.Fset.File(obj.Pos()).Name()
933 if strings.HasSuffix(path, "_test.go") {
934 if obj.Parent() != nil && obj.Parent().Parent() != nil && obj.Parent().Parent().Parent() == nil {
935 // object's scope is the package, whose
936 // parent is the file, whose parent is nil
938 // (4.9) functions use package-level variables they assign to iff in tests (sinks for benchmarks)
939 // (9.7) variable _reads_ use variables, writes do not, except in tests
940 g.seeAndUse(obj, owningObject(fn), edgeTestSink)
949 // Find constants being used in non-function contexts
950 for _, obj := range pkg.TypesInfo.Uses {
951 _, ok := obj.(*types.Const)
955 g.seeAndUse(obj, nil, edgeUsedConstant)
958 var fns []*types.Func
961 for _, f := range pkg.Files {
962 ast.Inspect(f, func(n ast.Node) bool {
964 pop := stack[len(stack)-1]
965 stack = stack[:len(stack)-1]
966 if _, ok := pop.(*ast.FuncDecl); ok {
967 fns = fns[:len(fns)-1]
976 stack = append(stack, n)
977 switch n := n.(type) {
979 fn = pkg.TypesInfo.ObjectOf(n.Name).(*types.Func)
980 fns = append(fns, fn)
985 groups := astutil.GroupSpecs(pkg.Fset, n.Specs)
986 for _, specs := range groups {
990 for _, spec := range specs {
991 for _, name := range spec.(*ast.ValueSpec).Names {
992 obj := pkg.TypesInfo.ObjectOf(name)
993 // (10.1) const groups
994 g.seeAndUse(obj, cg, edgeConstGroup)
995 g.use(cg, obj, edgeConstGroup)
1001 for _, spec := range n.Specs {
1002 v := spec.(*ast.ValueSpec)
1003 for _, name := range v.Names {
1004 T := pkg.TypesInfo.TypeOf(name)
1006 g.seeAndUse(T, fn, edgeVarDecl)
1008 // TODO(dh): we likely want to make
1009 // the type used by the variable, not
1010 // the package containing the
1011 // variable. But then we have to take
1012 // special care of blank identifiers.
1013 g.seeAndUse(T, nil, edgeVarDecl)
1019 for _, spec := range n.Specs {
1020 // go/types doesn't provide a way to go from a
1021 // types.Named to the named type it was based on
1022 // (the t1 in type t2 t1). Therefore we walk the
1023 // AST and process GenDecls.
1025 // (2.2) named types use the type they're based on
1026 v := spec.(*ast.TypeSpec)
1027 T := pkg.TypesInfo.TypeOf(v.Type)
1028 obj := pkg.TypesInfo.ObjectOf(v.Name)
1031 g.use(T, obj, edgeType)
1032 g.typ(obj.Type(), nil)
1036 aliasFor := obj.(*types.TypeName).Type()
1037 // (2.3) named types use all their aliases. we can't easily track uses of aliases
1038 if isIrrelevant(aliasFor) {
1039 // We do not track the type this is an
1040 // alias for (for example builtins), so
1041 // just mark the alias used.
1043 // FIXME(dh): what about aliases declared inside functions?
1044 g.use(obj, nil, edgeAlias)
1047 g.seeAndUse(obj, aliasFor, edgeAlias)
1057 for _, m := range pkg.IR.Members {
1058 switch m := m.(type) {
1059 case *ir.NamedConst:
1060 // nothing to do, we collect all constants from Defs
1062 if m.Object() != nil {
1064 if m.Object().Exported() {
1065 // (1.3) packages use exported variables
1066 g.use(m.Object(), nil, edgeExportedVariable)
1070 mObj := owningObject(m)
1074 //lint:ignore SA9003 handled implicitly
1075 if m.Name() == "init" {
1076 // (1.5) packages use init functions
1078 // This is handled implicitly. The generated init
1079 // function has no object, thus everything in it will
1080 // be owned by the package.
1082 // This branch catches top-level functions, not methods.
1083 if m.Object() != nil && m.Object().Exported() {
1084 // (1.2) packages use exported functions
1085 g.use(mObj, nil, edgeExportedFunction)
1087 if m.Name() == "main" && pkg.Pkg.Name() == "main" {
1088 // (1.7) packages use the main function iff in the main package
1089 g.use(mObj, nil, edgeMainFunction)
1091 if pkg.Pkg.Path() == "runtime" && runtimeFuncs[m.Name()] {
1092 // (9.8) runtime functions that may be called from user code via the compiler
1093 g.use(mObj, nil, edgeRuntimeFunction)
1095 if m.Source() != nil {
1096 doc := m.Source().(*ast.FuncDecl).Doc
1098 for _, cmt := range doc.List {
1099 if strings.HasPrefix(cmt.Text, "//go:cgo_export_") {
1100 // (1.6) packages use functions exported to cgo
1101 g.use(mObj, nil, edgeCgoExported)
1109 if m.Object().Exported() {
1110 // (1.1) packages use exported named types
1111 g.use(m.Object(), nil, edgeExportedType)
1113 g.typ(m.Type(), nil)
1115 panic(fmt.Sprintf("unreachable: %T", m))
1119 // OPT(dh): can we find meaningful initial capacities for these slices?
1120 var ifaces []*types.Interface
1121 var notIfaces []types.Type
1123 for t := range g.seenTypes {
1124 switch t := t.(type) {
1125 case *types.Interface:
1126 // OPT(dh): (8.1) we only need interfaces that have unexported methods
1127 ifaces = append(ifaces, t)
1129 if _, ok := t.Underlying().(*types.Interface); !ok {
1130 notIfaces = append(notIfaces, t)
1135 // (8.0) handle interfaces
1136 for _, t := range notIfaces {
1137 ms := pkg.IR.Prog.MethodSets.MethodSet(t)
1138 for _, iface := range ifaces {
1139 if sels, ok := g.implements(t, iface, ms); ok {
1140 for _, sel := range sels {
1141 g.useMethod(t, sel, t, edgeImplements)
1147 type ignoredKey struct {
1151 ignores := map[ignoredKey]struct{}{}
1152 for _, dir := range pkg.Directives {
1153 if dir.Command != "ignore" && dir.Command != "file-ignore" {
1156 if len(dir.Arguments) == 0 {
1159 for _, check := range strings.Split(dir.Arguments[0], ",") {
1160 if check == "U1000" {
1161 pos := pkg.Fset.PositionFor(dir.Node.Pos(), false)
1163 switch dir.Command {
1176 ignores[key] = struct{}{}
1182 if len(ignores) > 0 {
1183 // all objects annotated with a //lint:ignore U1000 are considered used
1184 for obj := range g.Nodes {
1185 if obj, ok := obj.(types.Object); ok {
1186 pos := pkg.Fset.PositionFor(obj.Pos(), false)
1195 _, ok := ignores[key1]
1197 _, ok = ignores[key2]
1200 g.use(obj, nil, edgeIgnored)
1202 // use methods and fields of ignored types
1203 if obj, ok := obj.(*types.TypeName); ok {
1204 if typ, ok := obj.Type().(*types.Named); ok {
1205 for i := 0; i < typ.NumMethods(); i++ {
1206 g.use(typ.Method(i), nil, edgeIgnored)
1209 if typ, ok := obj.Type().Underlying().(*types.Struct); ok {
1210 for i := 0; i < typ.NumFields(); i++ {
1211 g.use(typ.Field(i), nil, edgeIgnored)
1221 func (g *graph) useMethod(t types.Type, sel *types.Selection, by interface{}, kind edgeKind) {
1226 base := typeutil.Dereference(t).Underlying().(*types.Struct)
1227 for _, idx := range path[:len(path)-1] {
1228 next := base.Field(idx)
1229 // (6.3) structs use embedded fields that help implement interfaces
1231 g.seeAndUse(next, base, edgeProvidesMethod)
1232 base, _ = typeutil.Dereference(next.Type()).Underlying().(*types.Struct)
1235 g.seeAndUse(obj, by, kind)
1238 func owningObject(fn *ir.Function) types.Object {
1239 if fn.Object() != nil {
1242 if fn.Parent() != nil {
1243 return owningObject(fn.Parent())
1248 func (g *graph) function(fn *ir.Function) {
1249 if fn.Package() != nil && fn.Package() != g.pkg.IR {
1253 if _, ok := g.seenFns[fn]; ok {
1256 g.seenFns[fn] = struct{}{}
1258 // (4.1) functions use all their arguments, return parameters and receivers
1259 g.signature(fn.Signature, owningObject(fn))
1261 for _, anon := range fn.AnonFuncs {
1262 // (4.2) functions use anonymous functions defined beneath them
1264 // This fact is expressed implicitly. Anonymous functions have
1265 // no types.Object, so their owner is the surrounding
1271 func (g *graph) typ(t types.Type, parent types.Type) {
1272 if _, ok := g.seenTypes[t]; ok {
1276 if t, ok := t.(*types.Named); ok && t.Obj().Pkg() != nil {
1277 if t.Obj().Pkg() != g.pkg.Pkg {
1282 g.seenTypes[t] = struct{}{}
1283 if isIrrelevant(t) {
1288 switch t := t.(type) {
1290 for i := 0; i < t.NumFields(); i++ {
1292 if t.Field(i).Exported() {
1293 // (6.2) structs use exported fields
1294 g.use(t.Field(i), t, edgeExportedField)
1295 } else if t.Field(i).Name() == "_" {
1296 g.use(t.Field(i), t, edgeBlankField)
1297 } else if isNoCopyType(t.Field(i).Type()) {
1298 // (6.1) structs use fields of type NoCopy sentinel
1299 g.use(t.Field(i), t, edgeNoCopySentinel)
1300 } else if parent == nil {
1301 // (11.1) anonymous struct types use all their fields.
1302 g.use(t.Field(i), t, edgeAnonymousStruct)
1304 if t.Field(i).Anonymous() {
1305 // does the embedded field contribute exported methods to the method set?
1306 T := t.Field(i).Type()
1307 if _, ok := T.Underlying().(*types.Pointer); !ok {
1308 // An embedded field is addressable, so check
1309 // the pointer type to get the full method set
1310 T = types.NewPointer(T)
1312 ms := g.pkg.IR.Prog.MethodSets.MethodSet(T)
1313 for j := 0; j < ms.Len(); j++ {
1314 if ms.At(j).Obj().Exported() {
1315 // (6.4) structs use embedded fields that have exported methods (recursively)
1316 g.use(t.Field(i), t, edgeExtendsExportedMethodSet)
1321 seen := map[*types.Struct]struct{}{}
1322 var hasExportedField func(t types.Type) bool
1323 hasExportedField = func(T types.Type) bool {
1324 t, ok := typeutil.Dereference(T).Underlying().(*types.Struct)
1328 if _, ok := seen[t]; ok {
1331 seen[t] = struct{}{}
1332 for i := 0; i < t.NumFields(); i++ {
1334 if field.Exported() {
1337 if field.Embedded() && hasExportedField(field.Type()) {
1343 // does the embedded field contribute exported fields?
1344 if hasExportedField(t.Field(i).Type()) {
1345 // (6.5) structs use embedded structs that have exported fields (recursively)
1346 g.use(t.Field(i), t, edgeExtendsExportedFields)
1350 g.variable(t.Field(i))
1355 // (9.3) types use their underlying and element types
1356 g.seeAndUse(t.Underlying(), t, edgeUnderlyingType)
1357 g.seeAndUse(t.Obj(), t, edgeTypeName)
1358 g.seeAndUse(t, t.Obj(), edgeNamedType)
1360 // (2.4) named types use the pointer type
1361 if _, ok := t.Underlying().(*types.Interface); !ok && t.NumMethods() > 0 {
1362 g.seeAndUse(types.NewPointer(t), t, edgePointerType)
1365 for i := 0; i < t.NumMethods(); i++ {
1367 // don't use trackExportedIdentifier here, we care about
1368 // all exported methods, even in package main or in tests.
1369 if t.Method(i).Exported() {
1370 // (2.1) named types use exported methods
1371 g.use(t.Method(i), t, edgeExportedMethod)
1373 g.function(g.pkg.IR.Prog.FuncValue(t.Method(i)))
1376 g.typ(t.Underlying(), t)
1378 // (9.3) types use their underlying and element types
1379 g.seeAndUse(t.Elem(), t, edgeElementType)
1380 g.typ(t.Elem(), nil)
1382 // (9.3) types use their underlying and element types
1383 g.seeAndUse(t.Elem(), t, edgeElementType)
1384 // (9.3) types use their underlying and element types
1385 g.seeAndUse(t.Key(), t, edgeKeyType)
1386 g.typ(t.Elem(), nil)
1388 case *types.Signature:
1390 case *types.Interface:
1391 for i := 0; i < t.NumMethods(); i++ {
1393 // (8.3) All interface methods are marked as used
1394 g.seeAndUse(m, t, edgeInterfaceMethod)
1395 g.seeAndUse(m.Type().(*types.Signature), m, edgeSignature)
1396 g.signature(m.Type().(*types.Signature), nil)
1398 for i := 0; i < t.NumEmbeddeds(); i++ {
1399 tt := t.EmbeddedType(i)
1400 // (8.4) All embedded interfaces are marked as used
1401 g.seeAndUse(tt, t, edgeEmbeddedInterface)
1404 // (9.3) types use their underlying and element types
1405 g.seeAndUse(t.Elem(), t, edgeElementType)
1406 g.typ(t.Elem(), nil)
1407 case *types.Pointer:
1408 // (9.3) types use their underlying and element types
1409 g.seeAndUse(t.Elem(), t, edgeElementType)
1410 g.typ(t.Elem(), nil)
1412 // (9.3) types use their underlying and element types
1413 g.seeAndUse(t.Elem(), t, edgeElementType)
1414 g.typ(t.Elem(), nil)
1416 for i := 0; i < t.Len(); i++ {
1417 // (9.3) types use their underlying and element types
1418 g.seeAndUse(t.At(i).Type(), t, edgeTupleElement|edgeType)
1419 g.typ(t.At(i).Type(), nil)
1422 panic(fmt.Sprintf("unreachable: %T", t))
1426 func (g *graph) variable(v *types.Var) {
1427 // (9.2) variables use their types
1428 g.seeAndUse(v.Type(), v, edgeType)
1429 g.typ(v.Type(), nil)
1432 func (g *graph) signature(sig *types.Signature, fn types.Object) {
1433 var user interface{} = fn
1438 if sig.Recv() != nil {
1439 g.seeAndUse(sig.Recv().Type(), user, edgeReceiver|edgeType)
1440 g.typ(sig.Recv().Type(), nil)
1442 for i := 0; i < sig.Params().Len(); i++ {
1443 param := sig.Params().At(i)
1444 g.seeAndUse(param.Type(), user, edgeFunctionArgument|edgeType)
1445 g.typ(param.Type(), nil)
1447 for i := 0; i < sig.Results().Len(); i++ {
1448 param := sig.Results().At(i)
1449 g.seeAndUse(param.Type(), user, edgeFunctionResult|edgeType)
1450 g.typ(param.Type(), nil)
1454 func (g *graph) instructions(fn *ir.Function) {
1455 fnObj := owningObject(fn)
1456 for _, b := range fn.Blocks {
1457 for _, instr := range b.Instrs {
1458 ops := instr.Operands(nil)
1459 switch instr.(type) {
1461 // (9.7) variable _reads_ use variables, writes do not
1466 for _, arg := range ops {
1467 walkPhi(*arg, func(v ir.Value) {
1468 switch v := v.(type) {
1470 // (4.3) functions use closures and bound methods.
1471 // (4.5) functions use functions they call
1472 // (9.5) instructions use their operands
1473 // (4.4) functions use functions they return. we assume that someone else will call the returned function
1474 if owningObject(v) != nil {
1475 g.seeAndUse(owningObject(v), fnObj, edgeInstructionOperand)
1479 // (9.6) instructions use their operands' types
1480 g.seeAndUse(v.Type(), fnObj, edgeType)
1481 g.typ(v.Type(), nil)
1483 if v.Object() != nil {
1484 // (9.5) instructions use their operands
1485 g.seeAndUse(v.Object(), fnObj, edgeInstructionOperand)
1490 if v, ok := instr.(ir.Value); ok {
1491 if _, ok := v.(*ir.Range); !ok {
1492 // See https://github.com/golang/go/issues/19670
1494 // (4.8) instructions use their types
1495 // (9.4) conversions use the type they convert to
1496 g.seeAndUse(v.Type(), fnObj, edgeType)
1497 g.typ(v.Type(), nil)
1500 switch instr := instr.(type) {
1502 st := instr.X.Type().Underlying().(*types.Struct)
1503 field := st.Field(instr.Field)
1504 // (4.7) functions use fields they access
1505 g.seeAndUse(field, fnObj, edgeFieldAccess)
1507 st := typeutil.Dereference(instr.X.Type()).Underlying().(*types.Struct)
1508 field := st.Field(instr.Field)
1509 // (4.7) functions use fields they access
1510 g.seeAndUse(field, fnObj, edgeFieldAccess)
1512 // nothing to do, handled generically by operands
1516 // handled generically as an instruction operand
1518 // (4.5) functions use functions/interface methods they call
1519 g.seeAndUse(c.Method, fnObj, edgeInterfaceCall)
1522 // nothing to do, handled generically by operands
1523 case *ir.ChangeType:
1524 // conversion type handled generically
1526 s1, ok1 := typeutil.Dereference(instr.Type()).Underlying().(*types.Struct)
1527 s2, ok2 := typeutil.Dereference(instr.X.Type()).Underlying().(*types.Struct)
1529 // Converting between two structs. The fields are
1530 // relevant for the conversion, but only if the
1531 // fields are also used outside of the conversion.
1532 // Mark fields as used by each other.
1534 assert(s1.NumFields() == s2.NumFields())
1535 for i := 0; i < s1.NumFields(); i++ {
1538 // (5.1) when converting between two equivalent structs, the fields in
1539 // either struct use each other. the fields are relevant for the
1540 // conversion, but only if the fields are also accessed outside the
1542 g.seeAndUse(s1.Field(i), s2.Field(i), edgeStructConversion)
1543 g.seeAndUse(s2.Field(i), s1.Field(i), edgeStructConversion)
1546 case *ir.MakeInterface:
1547 // nothing to do, handled generically by operands
1549 // nothing to do, handled generically by operands
1551 // nothing to do, the deferred functions are already marked use by defering them.
1553 // to unsafe.Pointer
1554 if typ, ok := instr.Type().(*types.Basic); ok && typ.Kind() == types.UnsafePointer {
1555 if ptr, ok := instr.X.Type().Underlying().(*types.Pointer); ok {
1556 if st, ok := ptr.Elem().Underlying().(*types.Struct); ok {
1557 for i := 0; i < st.NumFields(); i++ {
1558 // (5.2) when converting to or from unsafe.Pointer, mark all fields as used.
1559 g.seeAndUse(st.Field(i), fnObj, edgeUnsafeConversion)
1564 // from unsafe.Pointer
1565 if typ, ok := instr.X.Type().(*types.Basic); ok && typ.Kind() == types.UnsafePointer {
1566 if ptr, ok := instr.Type().Underlying().(*types.Pointer); ok {
1567 if st, ok := ptr.Elem().Underlying().(*types.Struct); ok {
1568 for i := 0; i < st.NumFields(); i++ {
1569 // (5.2) when converting to or from unsafe.Pointer, mark all fields as used.
1570 g.seeAndUse(st.Field(i), fnObj, edgeUnsafeConversion)
1575 case *ir.TypeAssert:
1576 // nothing to do, handled generically by instruction
1577 // type (possibly a tuple, which contains the asserted
1578 // to type). redundantly handled by the type of
1580 case *ir.MakeClosure:
1581 // nothing to do, handled generically by operands
1592 case *ir.Unreachable:
1602 case *ir.BlankStore:
1614 case *ir.StringLookup:
1630 case *ir.ChangeInterface:
1644 case *ir.TypeSwitch:
1646 case *ir.ConstantSwitch:
1649 panic(fmt.Sprintf("unreachable: %T", instr))
1655 // isNoCopyType reports whether a type represents the NoCopy sentinel
1656 // type. The NoCopy type is a named struct with no fields and exactly
1657 // one method `func Lock()` that is empty.
1659 // FIXME(dh): currently we're not checking that the function body is
1661 func isNoCopyType(typ types.Type) bool {
1662 st, ok := typ.Underlying().(*types.Struct)
1666 if st.NumFields() != 0 {
1670 named, ok := typ.(*types.Named)
1674 if named.NumMethods() != 1 {
1677 meth := named.Method(0)
1678 if meth.Name() != "Lock" {
1681 sig := meth.Type().(*types.Signature)
1682 if sig.Params().Len() != 0 || sig.Results().Len() != 0 {
1688 func walkPhi(v ir.Value, fn func(v ir.Value)) {
1689 phi, ok := v.(*ir.Phi)
1695 seen := map[ir.Value]struct{}{}
1696 var impl func(v *ir.Phi)
1697 impl = func(v *ir.Phi) {
1698 if _, ok := seen[v]; ok {
1701 seen[v] = struct{}{}
1702 for _, e := range v.Edges {
1703 if ev, ok := e.(*ir.Phi); ok {