deadweight is a tool that detects unused code using the Language Server Protocol (LSP).
The idea is simple: any LSP-compatible language server already knows how to enumerate symbols and find their references. deadweight leverages that to identify symbols with no real callers.
Current status: only Go is supported, via
gopls. The approach is language-agnostic by design and could be extended to any language with an LSP server.
- Symbol discovery — deadweight sends
textDocument/documentSymbolrequests to the language server for each source file, collecting all symbols (functions, types, struct fields, etc.) recursively. - Reference lookup — for each symbol, it sends a
textDocument/referencesrequest to find every location where that symbol is used. - Dead code detection — symbols that are not referenced are considered unused and reported.
- Go 1.22+
- gopls installed and available in your
PATH:
go install golang.org/x/tools/gopls@latestgo install github.com/theo303/deadweight/cmd/deadweight@latestOr clone and build locally:
git clone https://github.com/theo303/deadweight.git
cd deadweight
go build ./cmd/deadweightRun deadweight from the root of your project:
cd /path/to/your/project
deadweightIt will analyze all Go files in the current directory.
INFO MyHandler (Function) internal/api/handler.go:42:1
INFO OldMiddleware (Function) internal/middleware/legacy.go:17:1
INFO UserStatus (String) internal/model/user.go:88:5
Each line shows the symbol name, its kind, and its location (file:line:column).
deadweight can be configured with a YAML file to filter out symbols you don't want to track. You can set the config file using the -c flag. If this flag is not provided deadweight will also look for a .deadweight.yaml file at the current directory root.
deadweight -c deadweight.yml# Ignore embedded struct fields (e.g. sync.Mutex embedded in a struct)
ignore-embedded-fields: true
# Symbols in this section are ignored, references are not checked for them
ignore-symbols:
# Ignore common interface methods
- kinds:
- Method
names:
# name of method format: '(Type).Method', so we can use glob pattern.
- "*.Error"
- "*.String"
- "*.MarshalJSON"
- "*.UnmarshalJSON"
# Ignore all exported types (useful for library packages)
- kinds:
- Struct
- Interface
names:
- "[A-Z]*"
- kinds:
- Function
names:
- "main"
- "init"The kinds field accepts any of the LSP symbol kind names:
File, Module, Namespace, Package, Class, Method, Property, Field, Constructor, Enum, Interface, Function, Variable, Constant, String, Number, Boolean, Array, Object, Key, Null, EnumMember, Struct, Event, Operator, TypeParameter
Names support glob patterns using Go's filepath.Match syntax:
*matches any sequence of non-separator characters?matches any single character[abc]matches a character class
MIT — see LICENSE.