This is a Scala 3 tool to find unused code. It uses the TASTy files generated by the compiler and tasty-query to determine what code is used/unused.
See below for more details on setup and use.
To install the tool in an sbt project, add this to project/plugins.sbt, using the version number from the latest
GitHub release:
resolvers += "bondlink-maven-repo" at "https://maven.bondlink-cdn.com"
addSbtPlugin("bondlink" % "find-unused" % "x.y.z")Then update build.sbt to specify which top-level packages should be analyzed for unused code:
Global / findUnusedPackages := Seq("foo", "bar")To install the tool as a standalone CLI, download find-unused.jar from
the latest GitHub release.
A few sbt commands are available:
| Command | Description |
|---|---|
findUnusedExplicits |
Analyze the configured packages for unused explicit (i.e. non-implicit/given/using) code |
findUnusedGivens |
Analyze the configured packages for unused implicit/given/using code |
findUnusedImplicits |
An alias for findUnusedGivens |
findUnusedAll |
Analyze the configured packages for all types of unused code |
You can run the standalone CLI with:
java -jar /path/to/find-unused.jarThere are a couple options you must pass, as well as some optional ones:
| Option | Type | Description |
|---|---|---|
--package |
Required, repeated | The packages to analyze |
--classpath |
Required, repeated | The full classpath of your code and all dependencies |
--exclusion |
Optional, repeated | Code to exclude from unused warnings, see Exclusions |
--root-directory |
Optional | The path to the root of your codebase; used when reporting code positions |
java -jar /path/to/find-unused.jar \
--root-directory /path/to/your/code \
--package com.example.foo \
--package com.example.bar \
--classpath "$HOME/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala3-library_3/3.7.3/scala3-library_3-3.7.3.jar" \
--classpath ... \
--exclusion 'src=.*/src_managed/.*' \
--exclusion 'sym=^com\.example\.MyClass\.(foo|bar)$'You may wish to exclude some code from being reported as unused. The tool supports two types of exclusions:
| Name | Description |
|---|---|
src |
Exclude all code in files that match the given regex |
sym |
Exclude all code whose symbols match the given regex |
You can define exclusions using the findUnusedExclusions setting:
Global / findUnusedExclusions := Seq(
FindUnusedExclusion(src = ".*/src_managed/.*".r),
FindUnusedExclusion(sym = """^com\\.example\\.MyClass\\.(foo|bar)$""".r),
FindUnusedExclusion(src = "...".r, sym = "...".r),
)As of Scala 3.7.2, the TASTy representation of some inline and macro-related methods does not include references to
the given/implicit instances that they summon -- scala/scala3#22701
This includes:
scala.compiletime.summonAllscala.compiletime.summonFromscala.quoted.Expr.summon- Uses of
scala.compiletime.summonInlinein macros
The end result is that any instances that are only resolved by these methods will be reported as unused.
This is especially problematic for derivation, which often uses summonFrom. For example, with this code using
circe derivation:
import io.circe.Decoder
case class Foo(int: Int) derives Decoder
case class Bar(foo: Foo) derives DecoderFoo's derived Decoder will be reported as unused because circe derivation uses summonFrom. The Decoder is
required and used by Bar's derived Decoder.
As of Scala 3.7.2, the TASTy representation of calls to transparent inline methods is equivalent to the TASTy
representation of the body of the transparent inline method -- there is no indication that the transparent inline
method was called.
For example:
transparent inline def foo(): Int = 1
val bar = foo()The TASTy representation for val bar does not include a reference to transparent inline def foo, it appears as if
val bar is simply defined as
val bar = 1The end result is that transparent inline defs are reported as unused even when they are in fact used.
At the moment this tool only works when all projects in your build use the same Scala version, and that version is Scala 3.7.x.
Support may be added in the future for multiple Scala versions within the same build or for older Scala 3 versions.
You can use the sbt plugin to generate a launch.json config file that can be used in Visual Studio Code to debug find-unused.
To debug a project that uses the sbt plugin:
- Load
sbtin the project directory - Run one of the available sbt commands:
findUnusedExplicitsDebugConfig,findUnusedGivensDebugConfig, orfindUnusedAllDebugConfig - Copy the JSON that's printed out
- Clone
find-unused - Create
/path/to/find-unused/.vscode/launch.jsonusing the JSON from step 3 - Open the
find-unuseddirectory in VS Code - Install and setup Metals
- Import the sbt build with Metals and wait for completion
- Set any breakpoints you want in
find-unusedand start debugging