1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 /* 6 The deadcode command reports unreachable functions in Go programs. 7 8 Usage: deadcode [flags] package... 9 10 The deadcode command loads a Go program from source then uses Rapid 11 Type Analysis (RTA) to build a call graph of all the functions 12 reachable from the program's main function. Any functions that are not 13 reachable are reported as dead code, grouped by package. 14 15 Packages are expressed in the notation of 'go list' (or other 16 underlying build system if you are using an alternative 17 golang.org/x/go/packages driver). Only executable (main) packages are 18 considered starting points for the analysis. 19 20 The -test flag causes it to analyze test executables too. Tests 21 sometimes make use of functions that would otherwise appear to be dead 22 code, and public API functions reported as dead with -test indicate 23 possible gaps in your test coverage. Bear in mind that an Example test 24 function without an "Output:" comment is merely documentation: 25 it is dead code, and does not contribute coverage. 26 27 The -filter flag restricts results to packages that match the provided 28 regular expression; its default value is the module name of the first 29 package. Use -filter= to display all results. 30 31 Example: show all dead code within the gopls module: 32 33 $ deadcode -test golang.org/x/tools/gopls/... 34 35 The analysis can soundly analyze dynamic calls though func values, 36 interface methods, and reflection. However, it does not currently 37 understand the aliasing created by //go:linkname directives, so it 38 will fail to recognize that calls to a linkname-annotated function 39 with no body in fact dispatch to the function named in the annotation. 40 This may result in the latter function being spuriously reported as dead. 41 42 By default, the tool does not report dead functions in generated files, 43 as determined by the special comment described in 44 https://go.dev/s/generatedcode. Use the -generated flag to include them. 45 46 In any case, just because a function is reported as dead does not mean 47 it is unconditionally safe to delete it. For example, a dead function 48 may be referenced by another dead function, and a dead method may be 49 required to satisfy an interface that is never called. 50 Some judgement is required. 51 52 The analysis is valid only for a single GOOS/GOARCH/-tags configuration, 53 so a function reported as dead may be live in a different configuration. 54 Consider running the tool once for each configuration of interest. 55 Consider using a line-oriented output format (see below) to make it 56 easier to compute the intersection of results across all runs. 57 58 # Output 59 60 The command supports three output formats. 61 62 With no flags, the command prints the name and location of each dead 63 function in the form of a typical compiler diagnostic, for example: 64 65 $ deadcode -f='{{range .Funcs}}{{println .Position}}{{end}}' -test ./gopls/... 66 gopls/internal/protocol/command.go:1206:6: unreachable func: openClientEditor 67 gopls/internal/template/parse.go:414:18: unreachable func: Parsed.WriteNode 68 gopls/internal/template/parse.go:419:18: unreachable func: wrNode.writeNode 69 70 With the -json flag, the command prints an array of Package 71 objects, as defined by the JSON schema (see below). 72 73 With the -f=template flag, the command executes the specified template 74 on each Package record. So, this template shows dead functions grouped 75 by package: 76 77 $ deadcode -f='{{println .Path}}{{range .Funcs}}{{printf "\t%s\n" .Name}}{{end}}{{println}}' -test ./gopls/... 78 golang.org/x/tools/gopls/internal/lsp 79 openClientEditor 80 81 golang.org/x/tools/gopls/internal/template 82 Parsed.WriteNode 83 wrNode.writeNode 84 85 # Why is a function not dead? 86 87 The -whylive=function flag explain why the named function is not dead 88 by showing an arbitrary shortest path to it from one of the main functions. 89 (To enumerate the functions in a program, or for more sophisticated 90 call graph queries, use golang.org/x/tools/cmd/callgraph.) 91 92 Fully static call paths are preferred over paths involving dynamic 93 edges, even if longer. Paths starting from a non-test package are 94 preferred over those from tests. Paths from main functions are 95 preferred over paths from init functions. 96 97 The result is a list of Edge objects (see JSON schema below). 98 Again, the -json and -f=template flags may be used to control 99 the formatting of the list of Edge objects. 100 The default format shows, for each edge in the path, whether the call 101 is static or dynamic, and its source line number. For example: 102 103 $ deadcode -whylive=bytes.Buffer.String -test ./cmd/deadcode/... 104 golang.org/x/tools/cmd/deadcode.main 105 static@L0117 --> golang.org/x/tools/go/packages.Load 106 static@L0262 --> golang.org/x/tools/go/packages.defaultDriver 107 static@L0305 --> golang.org/x/tools/go/packages.goListDriver 108 static@L0153 --> golang.org/x/tools/go/packages.goListDriver$1 109 static@L0154 --> golang.org/x/tools/go/internal/packagesdriver.GetSizesForArgsGolist 110 static@L0044 --> bytes.Buffer.String 111 112 # JSON schema 113 114 type Package struct { 115 Name string // declared name 116 Path string // full import path 117 Funcs []Function // list of dead functions within it 118 } 119 120 type Function struct { 121 Name string // name (sans package qualifier) 122 Position Position // file/line/column of function declaration 123 Generated bool // function is declared in a generated .go file 124 } 125 126 type Edge struct { 127 Initial string // initial entrypoint (main or init); first edge only 128 Kind string // = static | dynamic 129 Position Position // file/line/column of call site 130 Callee string // target of the call 131 } 132 133 type Position struct { 134 File string // name of file 135 Line, Col int // line and byte index, both 1-based 136 } 137 */ 138 package main 139