13 "golang.org/x/tools/go/analysis"
14 "honnef.co/go/tools/code"
15 "honnef.co/go/tools/go/types/typeutil"
16 "honnef.co/go/tools/internal/passes/buildir"
17 "honnef.co/go/tools/ir"
18 "honnef.co/go/tools/lint"
21 // The graph we construct omits nodes along a path that do not
22 // contribute any new information to the solution. For example, the
23 // full graph for a function with a receiver would be Func ->
24 // Signature -> Var -> Type. However, since signatures cannot be
25 // unused, and receivers are always considered used, we can compact
26 // the graph down to Func -> Type. This makes the graph smaller, but
29 // TODO(dh): conversions between structs mark fields as used, but the
30 // conversion itself isn't part of that subgraph. even if the function
31 // containing the conversion is unused, the fields will be marked as
34 // TODO(dh): we cannot observe function calls in assembly files.
39 - (1.1) exported named types (unless in package main)
40 - (1.2) exported functions (unless in package main)
41 - (1.3) exported variables (unless in package main)
42 - (1.4) exported constants (unless in package main)
43 - (1.5) init functions
44 - (1.6) functions exported to cgo
45 - (1.7) the main function iff in the main package
46 - (1.8) symbols linked via go:linkname
49 - (2.1) exported methods
50 - (2.2) the type they're based on
51 - (2.3) all their aliases. we can't easily track uses of aliases
52 because go/types turns them into uses of the aliased types. assume
53 that if a type is used, so are all of its aliases.
54 - (2.4) the pointer type. this aids with eagerly implementing
55 interfaces. if a method that implements an interface is defined on
56 a pointer receiver, and the pointer type is never used, but the
57 named type is, then we still want to mark the method as used.
59 - variables and constants use:
63 - (4.1) all their arguments, return parameters and receivers
64 - (4.2) anonymous functions defined beneath them
65 - (4.3) closures and bound methods.
66 this implements a simplified model where a function is used merely by being referenced, even if it is never called.
67 that way we don't have to keep track of closures escaping functions.
68 - (4.4) functions they return. we assume that someone else will call the returned function
69 - (4.5) functions/interface methods they call
70 - types they instantiate or convert to
71 - (4.7) fields they access
72 - (4.8) types of all instructions
73 - (4.9) package-level variables they assign to iff in tests (sinks for benchmarks)
76 - (5.1) when converting between two equivalent structs, the fields in
77 either struct use each other. the fields are relevant for the
78 conversion, but only if the fields are also accessed outside the
80 - (5.2) when converting to or from unsafe.Pointer, mark all fields as used.
83 - (6.1) fields of type NoCopy sentinel
84 - (6.2) exported fields
85 - (6.3) embedded fields that help implement interfaces (either fully implements it, or contributes required methods) (recursively)
86 - (6.4) embedded fields that have exported methods (recursively)
87 - (6.5) embedded structs that have exported fields (recursively)
89 - (7.1) field accesses use fields
90 - (7.2) fields use their types
92 - (8.0) How we handle interfaces:
93 - (8.1) We do not technically care about interfaces that only consist of
94 exported methods. Exported methods on concrete types are always
96 - Any concrete type implements all known interfaces. Even if it isn't
97 assigned to any interfaces in our code, the user may receive a value
98 of the type and expect to pass it back to us through an interface.
100 Concrete types use their methods that implement interfaces. If the
101 type is used, it uses those methods. Otherwise, it doesn't. This
102 way, types aren't incorrectly marked reachable through the edge
105 - (8.3) All interface methods are marked as used, even if they never get
106 called. This is to accommodate sum types (unexported interface
107 method that must exist but never gets called.)
109 - (8.4) All embedded interfaces are marked as used. This is an
110 extension of 8.3, but we have to explicitly track embedded
111 interfaces because in a chain C->B->A, B wouldn't be marked as
112 used by 8.3 just because it contributes A's methods to C.
115 - thunks and other generated wrappers call the real function
116 - (9.2) variables use their types
117 - (9.3) types use their underlying and element types
118 - (9.4) conversions use the type they convert to
119 - (9.5) instructions use their operands
120 - (9.6) instructions use their operands' types
121 - (9.7) variable _reads_ use variables, writes do not, except in tests
122 - (9.8) runtime functions that may be called from user code via the compiler
126 (10.1) if one constant out of a block of constants is used, mark all
127 of them used. a lot of the time, unused constants exist for the sake
128 of completeness. See also
129 https://github.com/dominikh/go-tools/issues/365
132 - (11.1) anonymous struct types use all their fields. we cannot
133 deduplicate struct types, as that leads to order-dependent
134 reportings. we can't not deduplicate struct types while still
135 tracking fields, because then each instance of the unnamed type in
136 the data flow chain will get its own fields, causing false
137 positives. Thus, we only accurately track fields of named struct
138 types, and assume that unnamed struct types use all their fields.
141 - Differences in whole program mode:
142 - (e2) types aim to implement all exported interfaces from all packages
143 - (e3) exported identifiers aren't automatically used. for fields and
144 methods this poses extra issues due to reflection. We assume
145 that all exported fields are used. We also maintain a list of
146 known reflection-based method callers.
150 func assert(b bool) {
152 panic("failed assertion")
156 func typString(obj types.Object) string {
157 switch obj := obj.(type) {
167 case *types.TypeName:
174 // /usr/lib/go/src/runtime/proc.go:433:6: func badmorestackg0 is unused (U1000)
176 // Functions defined in the Go runtime that may be called through
177 // compiler magic or via assembly.
178 var runtimeFuncs = map[string]bool{
179 // The first part of the list is copied from
180 // cmd/compile/internal/gc/builtin.go, var runtimeDecls
185 "panicmakeslicelen": true,
190 "goschedguarded": true,
196 "printcomplex": true,
198 "printpointer": true,
206 "concatstring2": true,
207 "concatstring3": true,
208 "concatstring4": true,
209 "concatstring5": true,
210 "concatstrings": true,
213 "slicebytetostring": true,
214 "slicebytetostringtmp": true,
215 "slicerunetostring": true,
216 "stringtoslicebyte": true,
217 "stringtoslicerune": true,
219 "slicestringcopy": true,
229 "convT2Enoptr": true,
231 "convT2Inoptr": true,
236 "panicdottypeE": true,
237 "panicdottypeI": true,
238 "panicnildottype": true,
244 "makemap_small": true,
246 "mapaccess1_fast32": true,
247 "mapaccess1_fast64": true,
248 "mapaccess1_faststr": true,
249 "mapaccess1_fat": true,
251 "mapaccess2_fast32": true,
252 "mapaccess2_fast64": true,
253 "mapaccess2_faststr": true,
254 "mapaccess2_fat": true,
256 "mapassign_fast32": true,
257 "mapassign_fast32ptr": true,
258 "mapassign_fast64": true,
259 "mapassign_fast64ptr": true,
260 "mapassign_faststr": true,
263 "mapdelete_fast32": true,
264 "mapdelete_fast64": true,
265 "mapdelete_faststr": true,
274 "writeBarrier": true,
275 "typedmemmove": true,
277 "typedslicecopy": true,
278 "selectnbsend": true,
279 "selectnbrecv": true,
280 "selectnbrecv2": true,
288 "memclrNoHeapPointers": true,
289 "memclrHasPointers": true,
300 "float64toint64": true,
301 "float64touint64": true,
302 "float64touint32": true,
303 "int64tofloat64": true,
304 "uint64tofloat64": true,
305 "uint32tofloat64": true,
306 "complex128div": true,
307 "racefuncenter": true,
308 "racefuncenterfp": true,
309 "racefuncexit": true,
312 "racereadrange": true,
313 "racewriterange": true,
316 "x86HasPOPCNT": true,
318 "arm64HasATOMICS": true,
320 // The second part of the list is extracted from assembly code in
321 // the standard library, with the exception of the runtime package itself
329 "badmorestackg0": true,
330 "badmorestackgsignal": true,
332 "callbackasm1": true,
333 "callCfunction": true,
334 "cgocallback_gofunc": true,
335 "cgocallbackg": true,
338 "debugCallCheck": true,
339 "debugCallWrap": true,
341 "entersyscall": true,
345 "externalthreadhandler": true,
349 "i386_set_ldt": true,
351 "init_thread_tls": true,
357 "nacl_sysinfo": true,
367 "racecallback": true,
368 "reflectcallmove": true,
376 "sigprofNonGo": true,
381 "syscall_chdir": true,
382 "syscall_chroot": true,
383 "syscall_close": true,
384 "syscall_dup2": true,
385 "syscall_execve": true,
386 "syscall_exit": true,
387 "syscall_fcntl": true,
388 "syscall_forkx": true,
389 "syscall_gethostname": true,
390 "syscall_getpid": true,
391 "syscall_ioctl": true,
392 "syscall_pipe": true,
393 "syscall_rawsyscall6": true,
394 "syscall_rawSyscall6": true,
395 "syscall_rawsyscall": true,
396 "syscall_RawSyscall": true,
397 "syscall_rawsysvicall6": true,
398 "syscall_setgid": true,
399 "syscall_setgroups": true,
400 "syscall_setpgid": true,
401 "syscall_setsid": true,
402 "syscall_setuid": true,
403 "syscall_syscall6": true,
404 "syscall_syscall": true,
405 "syscall_Syscall": true,
406 "syscall_sysvicall6": true,
407 "syscall_wait4": true,
408 "syscall_write": true,
420 TypesInfo *types.Info
421 TypesSizes types.Sizes
423 SrcFuncs []*ir.Function
426 type Checker struct {
431 initialPackages map[*types.Package]struct{}
432 allPackages map[*types.Package]struct{}
436 func NewChecker(wholeProgram bool) *Checker {
438 initialPackages: map[*types.Package]struct{}{},
439 allPackages: map[*types.Package]struct{}{},
440 WholeProgram: wholeProgram,
444 func (c *Checker) Analyzer() *analysis.Analyzer {
449 return &analysis.Analyzer{
453 Requires: []*analysis.Analyzer{buildir.Analyzer},
457 func (c *Checker) Run(pass *analysis.Pass) (interface{}, error) {
461 c.graph.wholeProgram = c.WholeProgram
462 c.graph.fset = pass.Fset
465 var visit func(pkg *types.Package)
466 visit = func(pkg *types.Package) {
467 if _, ok := c.allPackages[pkg]; ok {
470 c.allPackages[pkg] = struct{}{}
471 for _, imp := range pkg.Imports() {
477 c.initialPackages[pass.Pkg] = struct{}{}
480 irpkg := pass.ResultOf[buildir.Analyzer].(*buildir.IR)
485 TypesInfo: pass.TypesInfo,
486 TypesSizes: pass.TypesSizes,
488 SrcFuncs: irpkg.SrcFuncs,
491 c.processPkg(c.graph, pkg)
496 func (c *Checker) ProblemObject(fset *token.FileSet, obj types.Object) lint.Problem {
498 if sig, ok := obj.Type().(*types.Signature); ok && sig.Recv() != nil {
499 switch sig.Recv().Type().(type) {
500 case *types.Named, *types.Pointer:
501 typ := types.TypeString(sig.Recv().Type(), func(*types.Package) string { return "" })
502 if len(typ) > 0 && typ[0] == '*' {
503 name = fmt.Sprintf("(%s).%s", typ, obj.Name())
504 } else if len(typ) > 0 {
505 name = fmt.Sprintf("%s.%s", typ, obj.Name())
515 Pos: lint.DisplayPosition(fset, obj.Pos()),
516 Message: fmt.Sprintf("%s %s is unused", typString(obj), name),
521 func (c *Checker) Result() []types.Object {
524 out2 := make([]types.Object, 0, len(out))
525 for _, v := range out {
526 if _, ok := c.initialPackages[v.Pkg()]; !ok {
529 out2 = append(out2, v)
535 func (c *Checker) debugf(f string, v ...interface{}) {
537 fmt.Fprintf(c.Debug, f, v...)
541 func (graph *Graph) quieten(node *Node) {
545 switch obj := node.obj.(type) {
547 for i := 0; i < obj.NumMethods(); i++ {
549 if node, ok := graph.nodeMaybe(m); ok {
554 for i := 0; i < obj.NumFields(); i++ {
555 if node, ok := graph.nodeMaybe(obj.Field(i)); ok {
559 case *types.Interface:
560 for i := 0; i < obj.NumExplicitMethods(); i++ {
561 m := obj.ExplicitMethod(i)
562 if node, ok := graph.nodeMaybe(m); ok {
569 func (c *Checker) results() []types.Object {
571 // We never analyzed any packages
575 var out []types.Object
578 var ifaces []*types.Interface
579 var notIfaces []types.Type
581 // implement as many interfaces as possible
582 c.graph.seenTypes.Iterate(func(t types.Type, _ interface{}) {
583 switch t := t.(type) {
584 case *types.Interface:
585 if t.NumMethods() > 0 {
586 ifaces = append(ifaces, t)
589 if _, ok := t.Underlying().(*types.Interface); !ok {
590 notIfaces = append(notIfaces, t)
595 for pkg := range c.allPackages {
596 for _, iface := range interfacesFromExportData(pkg) {
597 if iface.NumMethods() > 0 {
598 ifaces = append(ifaces, iface)
605 seenTypes: &c.graph.seenTypes,
607 // (8.0) handle interfaces
608 // (e2) types aim to implement all exported interfaces from all packages
609 for _, t := range notIfaces {
610 // OPT(dh): it is unfortunate that we do not have access
611 // to a populated method set at this point.
612 ms := types.NewMethodSet(t)
613 for _, iface := range ifaces {
614 if sels, ok := c.graph.implements(t, iface, ms); ok {
615 for _, sel := range sels {
616 c.graph.useMethod(ctx, t, sel, t, edgeImplements)
624 debugNode := func(node *Node) {
626 c.debugf("n%d [label=\"Root\"];\n", node.id)
628 c.debugf("n%d [label=%q];\n", node.id, fmt.Sprintf("(%T) %s", node.obj, node.obj))
630 for _, e := range node.used {
631 for i := edgeKind(1); i < 64; i++ {
632 if e.kind.is(1 << i) {
633 c.debugf("n%d -> n%d [label=%q];\n", node.id, e.node.id, edgeKind(1<<i))
639 c.debugf("digraph{\n")
640 debugNode(c.graph.Root)
641 for _, v := range c.graph.Nodes {
644 c.graph.TypeNodes.Iterate(func(key types.Type, value interface{}) {
645 debugNode(value.(*Node))
651 c.graph.color(c.graph.Root)
652 // if a node is unused, don't report any of the node's
653 // children as unused. for example, if a function is unused,
654 // don't flag its receiver. if a named type is unused, don't
657 for _, v := range c.graph.Nodes {
660 c.graph.TypeNodes.Iterate(func(_ types.Type, value interface{}) {
661 c.graph.quieten(value.(*Node))
664 report := func(node *Node) {
669 c.debugf("n%d [color=purple];\n", node.id)
673 c.debugf("n%d [color=red];\n", node.id)
674 switch obj := node.obj.(type) {
676 // don't report unnamed variables (interface embedding)
677 if obj.Name() != "" || obj.IsField() {
678 out = append(out, obj)
682 if obj.Name() != "_" {
683 out = append(out, obj)
687 c.debugf("n%d [color=gray];\n", node.id)
689 for _, v := range c.graph.Nodes {
692 c.graph.TypeNodes.Iterate(func(_ types.Type, value interface{}) {
693 report(value.(*Node))
699 func (c *Checker) processPkg(graph *Graph, pkg *pkg) {
700 if pkg.Pkg.Path() == "unsafe" {
706 func objNodeKeyFor(fset *token.FileSet, obj types.Object) objNodeKey {
713 case *types.TypeName:
726 panic(fmt.Sprintf("unreachable: %T", obj))
729 position := fset.PositionFor(obj.Pos(), false)
742 otPkgName objType = iota
752 // An objNodeKey describes a types.Object node in the graph.
754 // Due to test variants we may end up with multiple instances of the
755 // same object, which is why we have to deduplicate based on their
756 // source position. And because export data lacks column information,
757 // we also have to incorporate the object's string representation in
760 // Previously we used the object's full string representation
761 // (types.ObjectString), but that causes a significant amount of
762 // allocations. Currently we're using the object's type and name, in
763 // the hope that it is impossible for two objects to have the same
764 // type, name and file position.
765 type objNodeKey struct {
766 position token.Position
772 // accessed atomically
775 // Safe for concurrent use
778 seenTypes typeutil.Map
783 // need synchronisation
785 TypeNodes typeutil.Map
786 Nodes map[interface{}]*Node
787 objNodes map[objNodeKey]*Node
790 type context struct {
793 seenFns map[string]struct{}
794 seenTypes *typeutil.Map
798 func NewGraph() *Graph {
800 Nodes: map[interface{}]*Node{},
801 objNodes: map[objNodeKey]*Node{},
803 g.Root = g.newNode(&context{}, nil)
807 func (g *Graph) color(root *Node) {
812 for _, e := range root.used {
817 type ConstGroup struct {
818 // give the struct a size to get unique pointers
822 func (ConstGroup) String() string { return "const group" }
836 // set during final graph walk if node is reachable
838 // a parent node (e.g. the struct type containing a field) is
839 // already unused, don't report children
843 func (g *Graph) nodeMaybe(obj types.Object) (*Node, bool) {
846 if node, ok := g.Nodes[obj]; ok {
852 func (g *Graph) node(ctx *context, obj interface{}) (node *Node, new bool) {
855 switch obj := obj.(type) {
857 if v := g.TypeNodes.At(obj); v != nil {
858 return v.(*Node), false
860 node := g.newNode(ctx, obj)
861 g.TypeNodes.Set(obj, node)
864 if node, ok := g.Nodes[obj]; ok {
868 key := objNodeKeyFor(g.fset, obj)
869 if onode, ok := g.objNodes[key]; ok {
873 node = g.newNode(ctx, obj)
875 g.objNodes[key] = node
878 if node, ok := g.Nodes[obj]; ok {
882 node = g.newNode(ctx, obj)
888 func (g *Graph) newNode(ctx *context, obj interface{}) *Node {
896 func (n *Node) use(node *Node, kind edgeKind) {
900 n.used = append(n.used, edge{node: node, kind: kind})
903 // isIrrelevant reports whether an object's presence in the graph is
904 // of any relevance. A lot of objects will never have outgoing edges,
905 // nor meaningful incoming ones. Examples are basic types and empty
906 // signatures, among many others.
908 // Dropping these objects should have no effect on correctness, but
909 // may improve performance. It also helps with debugging, as it
910 // greatly reduces the size of the graph.
911 func isIrrelevant(obj interface{}) bool {
912 if obj, ok := obj.(types.Object); ok {
913 switch obj := obj.(type) {
916 // We need to track package fields
919 if obj.Pkg() != nil && obj.Parent() == obj.Pkg().Scope() {
920 // We need to track package-level variables
923 return isIrrelevant(obj.Type())
928 if T, ok := obj.(types.Type); ok {
929 switch T := T.(type) {
931 return isIrrelevant(T.Elem())
933 return isIrrelevant(T.Elem())
937 for i := 0; i < T.Len(); i++ {
938 if !isIrrelevant(T.At(i).Type()) {
943 case *types.Signature:
947 for i := 0; i < T.Params().Len(); i++ {
948 if !isIrrelevant(T.Params().At(i)) {
952 for i := 0; i < T.Results().Len(); i++ {
953 if !isIrrelevant(T.Results().At(i)) {
958 case *types.Interface:
959 return T.NumMethods() == 0 && T.NumEmbeddeds() == 0
961 return isIrrelevant(T.Elem())
963 return isIrrelevant(T.Key()) && isIrrelevant(T.Elem())
965 return T.NumFields() == 0
967 return isIrrelevant(T.Elem())
975 func (ctx *context) see(obj interface{}) *Node {
976 if isIrrelevant(obj) {
981 // add new node to graph
982 node, _ := ctx.g.node(ctx, obj)
986 func (ctx *context) use(used, by interface{}, kind edgeKind) {
987 if isIrrelevant(used) {
992 if obj, ok := by.(types.Object); ok && obj.Pkg() != nil {
993 if !ctx.g.wholeProgram && obj.Pkg() != ctx.pkg.Pkg {
997 usedNode, new := ctx.g.node(ctx, used)
1000 ctx.g.Root.use(usedNode, kind)
1002 byNode, new := ctx.g.node(ctx, by)
1004 byNode.use(usedNode, kind)
1008 func (ctx *context) seeAndUse(used, by interface{}, kind edgeKind) *Node {
1009 node := ctx.see(used)
1010 ctx.use(used, by, kind)
1014 // trackExportedIdentifier reports whether obj should be considered
1015 // used due to being exported, checking various conditions that affect
1017 func (g *Graph) trackExportedIdentifier(ctx *context, obj types.Object) bool {
1018 if !obj.Exported() {
1019 // object isn't exported, the question is moot
1022 path := g.fset.Position(obj.Pos()).Filename
1024 // Example functions without "Output:" comments aren't being
1025 // run and thus don't show up in the graph.
1026 if strings.HasSuffix(path, "_test.go") && strings.HasPrefix(obj.Name(), "Example") {
1029 // whole program mode tracks exported identifiers accurately
1033 if ctx.pkg.Pkg.Name() == "main" && !strings.HasSuffix(path, "_test.go") {
1034 // exported identifiers in package main can't be imported.
1035 // However, test functions can be called, and xtest packages
1036 // even have access to exported identifiers.
1040 if strings.HasSuffix(path, "_test.go") {
1041 if strings.HasPrefix(obj.Name(), "Test") ||
1042 strings.HasPrefix(obj.Name(), "Benchmark") ||
1043 strings.HasPrefix(obj.Name(), "Example") {
1052 func (g *Graph) entry(pkg *pkg) {
1053 no := atomic.AddUint64(&g.nodeOffset, 1)
1057 nodeCounter: no * 1e9,
1058 seenFns: map[string]struct{}{},
1061 ctx.seenTypes = &g.seenTypes
1063 ctx.seenTypes = &typeutil.Map{}
1066 scopes := map[*types.Scope]*ir.Function{}
1067 for _, fn := range pkg.SrcFuncs {
1068 if fn.Object() != nil {
1069 scope := fn.Object().(*types.Func).Scope()
1074 for _, f := range pkg.Files {
1075 for _, cg := range f.Comments {
1076 for _, c := range cg.List {
1077 if strings.HasPrefix(c.Text, "//go:linkname ") {
1078 // FIXME(dh): we're looking at all comments. The
1079 // compiler only looks at comments in the
1080 // left-most column. The intention probably is to
1081 // only look at top-level comments.
1083 // (1.8) packages use symbols linked via go:linkname
1084 fields := strings.Fields(c.Text)
1085 if len(fields) == 3 {
1086 if m, ok := pkg.IR.Members[fields[1]]; ok {
1087 var obj types.Object
1088 switch m := m.(type) {
1094 panic(fmt.Sprintf("unhandled type: %T", m))
1097 ctx.seeAndUse(obj, nil, edgeLinkname)
1105 surroundingFunc := func(obj types.Object) *ir.Function {
1106 scope := obj.Parent()
1108 if fn := scopes[scope]; fn != nil {
1111 scope = scope.Parent()
1116 // IR form won't tell us about locally scoped types that aren't
1117 // being used. Walk the list of Defs to get all named types.
1119 // IR form also won't tell us about constants; use Defs and Uses
1120 // to determine which constants exist and which are being used.
1121 for _, obj := range pkg.TypesInfo.Defs {
1122 switch obj := obj.(type) {
1123 case *types.TypeName:
1124 // types are being handled by walking the AST
1127 fn := surroundingFunc(obj)
1128 if fn == nil && g.trackExportedIdentifier(ctx, obj) {
1129 // (1.4) packages use exported constants (unless in package main)
1130 ctx.use(obj, nil, edgeExportedConstant)
1132 g.typ(ctx, obj.Type(), nil)
1133 ctx.seeAndUse(obj.Type(), obj, edgeType)
1137 // Find constants being used inside functions, find sinks in tests
1138 for _, fn := range pkg.SrcFuncs {
1139 if fn.Object() != nil {
1140 ctx.see(fn.Object())
1146 ast.Inspect(node, func(node ast.Node) bool {
1147 switch node := node.(type) {
1149 obj, ok := pkg.TypesInfo.Uses[node]
1153 switch obj := obj.(type) {
1155 ctx.seeAndUse(obj, owningObject(fn), edgeUsedConstant)
1157 case *ast.AssignStmt:
1158 for _, expr := range node.Lhs {
1159 ident, ok := expr.(*ast.Ident)
1163 obj := pkg.TypesInfo.ObjectOf(ident)
1167 path := g.fset.File(obj.Pos()).Name()
1168 if strings.HasSuffix(path, "_test.go") {
1169 if obj.Parent() != nil && obj.Parent().Parent() != nil && obj.Parent().Parent().Parent() == nil {
1170 // object's scope is the package, whose
1171 // parent is the file, whose parent is nil
1173 // (4.9) functions use package-level variables they assign to iff in tests (sinks for benchmarks)
1174 // (9.7) variable _reads_ use variables, writes do not, except in tests
1175 ctx.seeAndUse(obj, owningObject(fn), edgeTestSink)
1184 // Find constants being used in non-function contexts
1185 for _, obj := range pkg.TypesInfo.Uses {
1186 _, ok := obj.(*types.Const)
1190 ctx.seeAndUse(obj, nil, edgeUsedConstant)
1193 var fns []*types.Func
1195 var stack []ast.Node
1196 for _, f := range pkg.Files {
1197 ast.Inspect(f, func(n ast.Node) bool {
1199 pop := stack[len(stack)-1]
1200 stack = stack[:len(stack)-1]
1201 if _, ok := pop.(*ast.FuncDecl); ok {
1202 fns = fns[:len(fns)-1]
1206 fn = fns[len(fns)-1]
1211 stack = append(stack, n)
1212 switch n := n.(type) {
1214 fn = pkg.TypesInfo.ObjectOf(n.Name).(*types.Func)
1215 fns = append(fns, fn)
1220 groups := code.GroupSpecs(pkg.Fset, n.Specs)
1221 for _, specs := range groups {
1225 for _, spec := range specs {
1226 for _, name := range spec.(*ast.ValueSpec).Names {
1227 obj := pkg.TypesInfo.ObjectOf(name)
1228 // (10.1) const groups
1229 ctx.seeAndUse(obj, cg, edgeConstGroup)
1230 ctx.use(cg, obj, edgeConstGroup)
1236 for _, spec := range n.Specs {
1237 v := spec.(*ast.ValueSpec)
1238 for _, name := range v.Names {
1239 T := pkg.TypesInfo.TypeOf(name)
1241 ctx.seeAndUse(T, fn, edgeVarDecl)
1243 // TODO(dh): we likely want to make
1244 // the type used by the variable, not
1245 // the package containing the
1246 // variable. But then we have to take
1247 // special care of blank identifiers.
1248 ctx.seeAndUse(T, nil, edgeVarDecl)
1254 for _, spec := range n.Specs {
1255 // go/types doesn't provide a way to go from a
1256 // types.Named to the named type it was based on
1257 // (the t1 in type t2 t1). Therefore we walk the
1258 // AST and process GenDecls.
1260 // (2.2) named types use the type they're based on
1261 v := spec.(*ast.TypeSpec)
1262 T := pkg.TypesInfo.TypeOf(v.Type)
1263 obj := pkg.TypesInfo.ObjectOf(v.Name)
1266 ctx.use(T, obj, edgeType)
1267 g.typ(ctx, obj.Type(), nil)
1271 aliasFor := obj.(*types.TypeName).Type()
1272 // (2.3) named types use all their aliases. we can't easily track uses of aliases
1273 if isIrrelevant(aliasFor) {
1274 // We do not track the type this is an
1275 // alias for (for example builtins), so
1276 // just mark the alias used.
1278 // FIXME(dh): what about aliases declared inside functions?
1279 ctx.use(obj, nil, edgeAlias)
1282 ctx.seeAndUse(obj, aliasFor, edgeAlias)
1292 for _, m := range pkg.IR.Members {
1293 switch m := m.(type) {
1294 case *ir.NamedConst:
1295 // nothing to do, we collect all constants from Defs
1297 if m.Object() != nil {
1299 if g.trackExportedIdentifier(ctx, m.Object()) {
1300 // (1.3) packages use exported variables (unless in package main)
1301 ctx.use(m.Object(), nil, edgeExportedVariable)
1305 mObj := owningObject(m)
1309 //lint:ignore SA9003 handled implicitly
1310 if m.Name() == "init" {
1311 // (1.5) packages use init functions
1313 // This is handled implicitly. The generated init
1314 // function has no object, thus everything in it will
1315 // be owned by the package.
1317 // This branch catches top-level functions, not methods.
1318 if m.Object() != nil && g.trackExportedIdentifier(ctx, m.Object()) {
1319 // (1.2) packages use exported functions (unless in package main)
1320 ctx.use(mObj, nil, edgeExportedFunction)
1322 if m.Name() == "main" && pkg.Pkg.Name() == "main" {
1323 // (1.7) packages use the main function iff in the main package
1324 ctx.use(mObj, nil, edgeMainFunction)
1326 if pkg.Pkg.Path() == "runtime" && runtimeFuncs[m.Name()] {
1327 // (9.8) runtime functions that may be called from user code via the compiler
1328 ctx.use(mObj, nil, edgeRuntimeFunction)
1330 if m.Source() != nil {
1331 doc := m.Source().(*ast.FuncDecl).Doc
1333 for _, cmt := range doc.List {
1334 if strings.HasPrefix(cmt.Text, "//go:cgo_export_") {
1335 // (1.6) packages use functions exported to cgo
1336 ctx.use(mObj, nil, edgeCgoExported)
1343 if m.Object() != nil {
1345 if g.trackExportedIdentifier(ctx, m.Object()) {
1346 // (1.1) packages use exported named types (unless in package main)
1347 ctx.use(m.Object(), nil, edgeExportedType)
1350 g.typ(ctx, m.Type(), nil)
1352 panic(fmt.Sprintf("unreachable: %T", m))
1356 if !g.wholeProgram {
1357 // When not in whole program mode we reset seenTypes after each package,
1358 // which means g.seenTypes only contains types of
1359 // interest to us. In whole program mode, we're better off
1360 // processing all interfaces at once, globally, both for
1361 // performance reasons and because in whole program mode we
1362 // actually care about all interfaces, not just the subset
1363 // that has unexported methods.
1365 var ifaces []*types.Interface
1366 var notIfaces []types.Type
1368 ctx.seenTypes.Iterate(func(t types.Type, _ interface{}) {
1369 switch t := t.(type) {
1370 case *types.Interface:
1371 // OPT(dh): (8.1) we only need interfaces that have unexported methods
1372 ifaces = append(ifaces, t)
1374 if _, ok := t.Underlying().(*types.Interface); !ok {
1375 notIfaces = append(notIfaces, t)
1380 // (8.0) handle interfaces
1381 for _, t := range notIfaces {
1382 ms := pkg.IR.Prog.MethodSets.MethodSet(t)
1383 for _, iface := range ifaces {
1384 if sels, ok := g.implements(t, iface, ms); ok {
1385 for _, sel := range sels {
1386 g.useMethod(ctx, t, sel, t, edgeImplements)
1394 func (g *Graph) useMethod(ctx *context, t types.Type, sel *types.Selection, by interface{}, kind edgeKind) {
1399 base := code.Dereference(t).Underlying().(*types.Struct)
1400 for _, idx := range path[:len(path)-1] {
1401 next := base.Field(idx)
1402 // (6.3) structs use embedded fields that help implement interfaces
1404 ctx.seeAndUse(next, base, edgeProvidesMethod)
1405 base, _ = code.Dereference(next.Type()).Underlying().(*types.Struct)
1408 ctx.seeAndUse(obj, by, kind)
1411 func owningObject(fn *ir.Function) types.Object {
1412 if fn.Object() != nil {
1415 if fn.Parent() != nil {
1416 return owningObject(fn.Parent())
1421 func (g *Graph) function(ctx *context, fn *ir.Function) {
1422 if fn.Package() != nil && fn.Package() != ctx.pkg.IR {
1426 name := fn.RelString(nil)
1427 if _, ok := ctx.seenFns[name]; ok {
1430 ctx.seenFns[name] = struct{}{}
1432 // (4.1) functions use all their arguments, return parameters and receivers
1433 g.signature(ctx, fn.Signature, owningObject(fn))
1434 g.instructions(ctx, fn)
1435 for _, anon := range fn.AnonFuncs {
1436 // (4.2) functions use anonymous functions defined beneath them
1438 // This fact is expressed implicitly. Anonymous functions have
1439 // no types.Object, so their owner is the surrounding
1441 g.function(ctx, anon)
1445 func (g *Graph) typ(ctx *context, t types.Type, parent types.Type) {
1449 if ctx.seenTypes.At(t) != nil {
1458 if t, ok := t.(*types.Named); ok && t.Obj().Pkg() != nil {
1459 if t.Obj().Pkg() != ctx.pkg.Pkg {
1467 ctx.seenTypes.Set(t, struct{}{})
1471 if isIrrelevant(t) {
1476 switch t := t.(type) {
1478 for i := 0; i < t.NumFields(); i++ {
1480 if t.Field(i).Exported() {
1481 // (6.2) structs use exported fields
1482 ctx.use(t.Field(i), t, edgeExportedField)
1483 } else if t.Field(i).Name() == "_" {
1484 ctx.use(t.Field(i), t, edgeBlankField)
1485 } else if isNoCopyType(t.Field(i).Type()) {
1486 // (6.1) structs use fields of type NoCopy sentinel
1487 ctx.use(t.Field(i), t, edgeNoCopySentinel)
1488 } else if parent == nil {
1489 // (11.1) anonymous struct types use all their fields.
1490 ctx.use(t.Field(i), t, edgeAnonymousStruct)
1492 if t.Field(i).Anonymous() {
1493 // (e3) exported identifiers aren't automatically used.
1494 if !g.wholeProgram {
1495 // does the embedded field contribute exported methods to the method set?
1496 T := t.Field(i).Type()
1497 if _, ok := T.Underlying().(*types.Pointer); !ok {
1498 // An embedded field is addressable, so check
1499 // the pointer type to get the full method set
1500 T = types.NewPointer(T)
1502 ms := ctx.pkg.IR.Prog.MethodSets.MethodSet(T)
1503 for j := 0; j < ms.Len(); j++ {
1504 if ms.At(j).Obj().Exported() {
1505 // (6.4) structs use embedded fields that have exported methods (recursively)
1506 ctx.use(t.Field(i), t, edgeExtendsExportedMethodSet)
1512 seen := map[*types.Struct]struct{}{}
1513 var hasExportedField func(t types.Type) bool
1514 hasExportedField = func(T types.Type) bool {
1515 t, ok := code.Dereference(T).Underlying().(*types.Struct)
1519 if _, ok := seen[t]; ok {
1522 seen[t] = struct{}{}
1523 for i := 0; i < t.NumFields(); i++ {
1525 if field.Exported() {
1528 if field.Embedded() && hasExportedField(field.Type()) {
1534 // does the embedded field contribute exported fields?
1535 if hasExportedField(t.Field(i).Type()) {
1536 // (6.5) structs use embedded structs that have exported fields (recursively)
1537 ctx.use(t.Field(i), t, edgeExtendsExportedFields)
1541 g.variable(ctx, t.Field(i))
1546 // (9.3) types use their underlying and element types
1547 ctx.seeAndUse(t.Underlying(), t, edgeUnderlyingType)
1548 ctx.seeAndUse(t.Obj(), t, edgeTypeName)
1549 ctx.seeAndUse(t, t.Obj(), edgeNamedType)
1551 // (2.4) named types use the pointer type
1552 if _, ok := t.Underlying().(*types.Interface); !ok && t.NumMethods() > 0 {
1553 ctx.seeAndUse(types.NewPointer(t), t, edgePointerType)
1556 for i := 0; i < t.NumMethods(); i++ {
1557 ctx.see(t.Method(i))
1558 // don't use trackExportedIdentifier here, we care about
1559 // all exported methods, even in package main or in tests.
1560 if t.Method(i).Exported() && !g.wholeProgram {
1561 // (2.1) named types use exported methods
1562 ctx.use(t.Method(i), t, edgeExportedMethod)
1564 g.function(ctx, ctx.pkg.IR.Prog.FuncValue(t.Method(i)))
1567 g.typ(ctx, t.Underlying(), t)
1569 // (9.3) types use their underlying and element types
1570 ctx.seeAndUse(t.Elem(), t, edgeElementType)
1571 g.typ(ctx, t.Elem(), nil)
1573 // (9.3) types use their underlying and element types
1574 ctx.seeAndUse(t.Elem(), t, edgeElementType)
1575 // (9.3) types use their underlying and element types
1576 ctx.seeAndUse(t.Key(), t, edgeKeyType)
1577 g.typ(ctx, t.Elem(), nil)
1578 g.typ(ctx, t.Key(), nil)
1579 case *types.Signature:
1580 g.signature(ctx, t, nil)
1581 case *types.Interface:
1582 for i := 0; i < t.NumMethods(); i++ {
1584 // (8.3) All interface methods are marked as used
1585 ctx.seeAndUse(m, t, edgeInterfaceMethod)
1586 ctx.seeAndUse(m.Type().(*types.Signature), m, edgeSignature)
1587 g.signature(ctx, m.Type().(*types.Signature), nil)
1589 for i := 0; i < t.NumEmbeddeds(); i++ {
1590 tt := t.EmbeddedType(i)
1591 // (8.4) All embedded interfaces are marked as used
1592 ctx.seeAndUse(tt, t, edgeEmbeddedInterface)
1595 // (9.3) types use their underlying and element types
1596 ctx.seeAndUse(t.Elem(), t, edgeElementType)
1597 g.typ(ctx, t.Elem(), nil)
1598 case *types.Pointer:
1599 // (9.3) types use their underlying and element types
1600 ctx.seeAndUse(t.Elem(), t, edgeElementType)
1601 g.typ(ctx, t.Elem(), nil)
1603 // (9.3) types use their underlying and element types
1604 ctx.seeAndUse(t.Elem(), t, edgeElementType)
1605 g.typ(ctx, t.Elem(), nil)
1607 for i := 0; i < t.Len(); i++ {
1608 // (9.3) types use their underlying and element types
1609 ctx.seeAndUse(t.At(i).Type(), t, edgeTupleElement|edgeType)
1610 g.typ(ctx, t.At(i).Type(), nil)
1613 panic(fmt.Sprintf("unreachable: %T", t))
1617 func (g *Graph) variable(ctx *context, v *types.Var) {
1618 // (9.2) variables use their types
1619 ctx.seeAndUse(v.Type(), v, edgeType)
1620 g.typ(ctx, v.Type(), nil)
1623 func (g *Graph) signature(ctx *context, sig *types.Signature, fn types.Object) {
1624 var user interface{} = fn
1629 if sig.Recv() != nil {
1630 ctx.seeAndUse(sig.Recv().Type(), user, edgeReceiver|edgeType)
1631 g.typ(ctx, sig.Recv().Type(), nil)
1633 for i := 0; i < sig.Params().Len(); i++ {
1634 param := sig.Params().At(i)
1635 ctx.seeAndUse(param.Type(), user, edgeFunctionArgument|edgeType)
1636 g.typ(ctx, param.Type(), nil)
1638 for i := 0; i < sig.Results().Len(); i++ {
1639 param := sig.Results().At(i)
1640 ctx.seeAndUse(param.Type(), user, edgeFunctionResult|edgeType)
1641 g.typ(ctx, param.Type(), nil)
1645 func (g *Graph) instructions(ctx *context, fn *ir.Function) {
1646 fnObj := owningObject(fn)
1647 for _, b := range fn.Blocks {
1648 for _, instr := range b.Instrs {
1649 ops := instr.Operands(nil)
1650 switch instr.(type) {
1652 // (9.7) variable _reads_ use variables, writes do not
1657 for _, arg := range ops {
1658 walkPhi(*arg, func(v ir.Value) {
1659 switch v := v.(type) {
1661 // (4.3) functions use closures and bound methods.
1662 // (4.5) functions use functions they call
1663 // (9.5) instructions use their operands
1664 // (4.4) functions use functions they return. we assume that someone else will call the returned function
1665 if owningObject(v) != nil {
1666 ctx.seeAndUse(owningObject(v), fnObj, edgeInstructionOperand)
1670 // (9.6) instructions use their operands' types
1671 ctx.seeAndUse(v.Type(), fnObj, edgeType)
1672 g.typ(ctx, v.Type(), nil)
1674 if v.Object() != nil {
1675 // (9.5) instructions use their operands
1676 ctx.seeAndUse(v.Object(), fnObj, edgeInstructionOperand)
1681 if v, ok := instr.(ir.Value); ok {
1682 if _, ok := v.(*ir.Range); !ok {
1683 // See https://github.com/golang/go/issues/19670
1685 // (4.8) instructions use their types
1686 // (9.4) conversions use the type they convert to
1687 ctx.seeAndUse(v.Type(), fnObj, edgeType)
1688 g.typ(ctx, v.Type(), nil)
1691 switch instr := instr.(type) {
1693 st := instr.X.Type().Underlying().(*types.Struct)
1694 field := st.Field(instr.Field)
1695 // (4.7) functions use fields they access
1696 ctx.seeAndUse(field, fnObj, edgeFieldAccess)
1698 st := code.Dereference(instr.X.Type()).Underlying().(*types.Struct)
1699 field := st.Field(instr.Field)
1700 // (4.7) functions use fields they access
1701 ctx.seeAndUse(field, fnObj, edgeFieldAccess)
1703 // nothing to do, handled generically by operands
1707 // handled generically as an instruction operand
1710 // (e3) special case known reflection-based method callers
1711 switch code.CallName(c) {
1712 case "net/rpc.Register", "net/rpc.RegisterName", "(*net/rpc.Server).Register", "(*net/rpc.Server).RegisterName":
1714 switch code.CallName(c) {
1715 case "net/rpc.Register":
1717 case "net/rpc.RegisterName":
1719 case "(*net/rpc.Server).Register":
1721 case "(*net/rpc.Server).RegisterName":
1724 walkPhi(arg, func(v ir.Value) {
1725 if v, ok := v.(*ir.MakeInterface); ok {
1726 walkPhi(v.X, func(vv ir.Value) {
1727 ms := ctx.pkg.IR.Prog.MethodSets.MethodSet(vv.Type())
1728 for i := 0; i < ms.Len(); i++ {
1729 if ms.At(i).Obj().Exported() {
1730 g.useMethod(ctx, vv.Type(), ms.At(i), fnObj, edgeNetRPCRegister)
1739 // (4.5) functions use functions/interface methods they call
1740 ctx.seeAndUse(c.Method, fnObj, edgeInterfaceCall)
1743 // nothing to do, handled generically by operands
1744 case *ir.ChangeType:
1745 // conversion type handled generically
1747 s1, ok1 := code.Dereference(instr.Type()).Underlying().(*types.Struct)
1748 s2, ok2 := code.Dereference(instr.X.Type()).Underlying().(*types.Struct)
1750 // Converting between two structs. The fields are
1751 // relevant for the conversion, but only if the
1752 // fields are also used outside of the conversion.
1753 // Mark fields as used by each other.
1755 assert(s1.NumFields() == s2.NumFields())
1756 for i := 0; i < s1.NumFields(); i++ {
1757 ctx.see(s1.Field(i))
1758 ctx.see(s2.Field(i))
1759 // (5.1) when converting between two equivalent structs, the fields in
1760 // either struct use each other. the fields are relevant for the
1761 // conversion, but only if the fields are also accessed outside the
1763 ctx.seeAndUse(s1.Field(i), s2.Field(i), edgeStructConversion)
1764 ctx.seeAndUse(s2.Field(i), s1.Field(i), edgeStructConversion)
1767 case *ir.MakeInterface:
1768 // nothing to do, handled generically by operands
1770 // nothing to do, handled generically by operands
1772 // nothing to do, the deferred functions are already marked use by defering them.
1774 // to unsafe.Pointer
1775 if typ, ok := instr.Type().(*types.Basic); ok && typ.Kind() == types.UnsafePointer {
1776 if ptr, ok := instr.X.Type().Underlying().(*types.Pointer); ok {
1777 if st, ok := ptr.Elem().Underlying().(*types.Struct); ok {
1778 for i := 0; i < st.NumFields(); i++ {
1779 // (5.2) when converting to or from unsafe.Pointer, mark all fields as used.
1780 ctx.seeAndUse(st.Field(i), fnObj, edgeUnsafeConversion)
1785 // from unsafe.Pointer
1786 if typ, ok := instr.X.Type().(*types.Basic); ok && typ.Kind() == types.UnsafePointer {
1787 if ptr, ok := instr.Type().Underlying().(*types.Pointer); ok {
1788 if st, ok := ptr.Elem().Underlying().(*types.Struct); ok {
1789 for i := 0; i < st.NumFields(); i++ {
1790 // (5.2) when converting to or from unsafe.Pointer, mark all fields as used.
1791 ctx.seeAndUse(st.Field(i), fnObj, edgeUnsafeConversion)
1796 case *ir.TypeAssert:
1797 // nothing to do, handled generically by instruction
1798 // type (possibly a tuple, which contains the asserted
1799 // to type). redundantly handled by the type of
1801 case *ir.MakeClosure:
1802 // nothing to do, handled generically by operands
1813 case *ir.Unreachable:
1823 case *ir.BlankStore:
1835 case *ir.StringLookup:
1851 case *ir.ChangeInterface:
1865 case *ir.TypeSwitch:
1867 case *ir.ConstantSwitch:
1870 panic(fmt.Sprintf("unreachable: %T", instr))
1876 // isNoCopyType reports whether a type represents the NoCopy sentinel
1877 // type. The NoCopy type is a named struct with no fields and exactly
1878 // one method `func Lock()` that is empty.
1880 // FIXME(dh): currently we're not checking that the function body is
1882 func isNoCopyType(typ types.Type) bool {
1883 st, ok := typ.Underlying().(*types.Struct)
1887 if st.NumFields() != 0 {
1891 named, ok := typ.(*types.Named)
1895 if named.NumMethods() != 1 {
1898 meth := named.Method(0)
1899 if meth.Name() != "Lock" {
1902 sig := meth.Type().(*types.Signature)
1903 if sig.Params().Len() != 0 || sig.Results().Len() != 0 {
1909 func walkPhi(v ir.Value, fn func(v ir.Value)) {
1910 phi, ok := v.(*ir.Phi)
1916 seen := map[ir.Value]struct{}{}
1917 var impl func(v *ir.Phi)
1918 impl = func(v *ir.Phi) {
1919 if _, ok := seen[v]; ok {
1922 seen[v] = struct{}{}
1923 for _, e := range v.Edges {
1924 if ev, ok := e.(*ir.Phi); ok {
1934 func interfacesFromExportData(pkg *types.Package) []*types.Interface {
1935 var out []*types.Interface
1936 scope := pkg.Scope()
1937 for _, name := range scope.Names() {
1938 obj := scope.Lookup(name)
1939 out = append(out, interfacesFromObject(obj)...)
1944 func interfacesFromObject(obj types.Object) []*types.Interface {
1945 var out []*types.Interface
1946 switch obj := obj.(type) {
1948 sig := obj.Type().(*types.Signature)
1949 for i := 0; i < sig.Results().Len(); i++ {
1950 out = append(out, interfacesFromObject(sig.Results().At(i))...)
1952 for i := 0; i < sig.Params().Len(); i++ {
1953 out = append(out, interfacesFromObject(sig.Params().At(i))...)
1955 case *types.TypeName:
1956 if named, ok := obj.Type().(*types.Named); ok {
1957 for i := 0; i < named.NumMethods(); i++ {
1958 out = append(out, interfacesFromObject(named.Method(i))...)
1961 if iface, ok := named.Underlying().(*types.Interface); ok {
1962 out = append(out, iface)
1966 // No call to Underlying here. We want unnamed interfaces
1967 // only. Named interfaces are gotten directly from the
1969 if iface, ok := obj.Type().(*types.Interface); ok {
1970 out = append(out, iface)
1973 case *types.Builtin:
1975 panic(fmt.Sprintf("unhandled type: %T", obj))