diff --git a/src/main/scala/higherkindness/rules_scala/used_deps/BUILD b/src/main/scala/higherkindness/rules_scala/used_deps/BUILD
new file mode 100644
index 000000000..7d425f4f0
--- /dev/null
+++ b/src/main/scala/higherkindness/rules_scala/used_deps/BUILD
@@ -0,0 +1,43 @@
+load("//rules:scalafmt.bzl", "scala_format_test")
+load("//rules:scala.bzl", "scala_library")
+
+scala_library(
+ name = "used_deps",
+ srcs = glob(["**/*.scala"]),
+ scala = "//external:scala_annex_scala",
+ visibility = ["//visibility:public"],
+ deps = [
+ "@scala_annex_scala_2_12_scala_compiler//jar",
+ "@scala_annex_scala_2_12_scala_reflect//jar",
+ ],
+ resource_jars = [
+ ":resources",
+ ],
+)
+
+_gen_plugin_xml_cmd = """
+cat > $@ << EOF
+
+ name
+ higherkindness.rules_scala.used_deps.UsedDepsPlugin
+
+"""
+
+genrule(
+ name = "gen-scalac-plugin.xml",
+ outs = ["scalac-plugin.xml"],
+ cmd = _gen_plugin_xml_cmd,
+)
+
+java_binary(
+ name = "resources",
+ classpath_resources = [
+ ":gen-scalac-plugin.xml",
+ ],
+ create_executable = False,
+)
+
+scala_format_test(
+ name = "format",
+ srcs = glob(["**/*.scala"]),
+)
diff --git a/src/main/scala/higherkindness/rules_scala/used_deps/plugin.scala b/src/main/scala/higherkindness/rules_scala/used_deps/plugin.scala
new file mode 100644
index 000000000..4ca81bfc6
--- /dev/null
+++ b/src/main/scala/higherkindness/rules_scala/used_deps/plugin.scala
@@ -0,0 +1,94 @@
+package higherkindness.rules_scala
+package used_deps
+
+import scala.reflect.io.AbstractFile
+import scala.reflect.io.NoAbstractFile
+import scala.reflect.internal.SymbolTable
+import scala.tools.nsc.Global
+import scala.tools.nsc.Phase
+import scala.tools.nsc.plugins.Plugin
+import scala.tools.nsc.plugins.PluginComponent
+import scala.util.matching.Regex
+
+import java.io.File
+
+final class UsedDepsPlugin(override val global: Global) extends Plugin {
+
+ override val name: String = "used-deps"
+ override val description: String = "tracks used dependencies"
+ override val components: List[PluginComponent] = usedDeps :: Nil
+
+ private object usedDeps extends PluginComponent {
+ override val global: Global = UsedDepsPlugin.this.global
+ override val phaseName: String = "unused-deps"
+ override val runsAfter: List[String] = global.refChecks.phaseName :: Nil
+
+ private[used_deps] var outputFile: Option[File] = None
+
+ override def newPhase(prev: Phase): Phase =
+ new StdPhase(prev) with UsedDepsPhase[global.type] {
+ val global = usedDeps.this.global
+ }
+ }
+
+ override val optionsHelp: Option[String] = Some(
+ " -P:unused-deps:out= Path to write output file (default: stdout)"
+ )
+
+ private implicit final class RegexInterpolator(sc: StringContext) {
+ def r = new Regex(sc.parts.mkString, sc.parts.tail.map(_ => "x"): _*)
+ }
+
+ override def init(options: List[String], error: String => Unit): Boolean = {
+ options.foreach {
+ case r"out=(.*)$out" =>
+ usedDeps.outputFile = Some(new File(out))
+ case arg =>
+ error(s"Unexpected argument: $arg")
+ }
+ true
+ }
+
+ {
+ hijackField(classOf[SymbolTable], "traceSymbolActivity", true)
+ }
+
+ if (global.traceSymbolActivity != true)
+ sys.error("unable to force tracing of symbol activity")
+
+ private[this] def hijackField[T](clazz: Class[_], name: String, newValue: T): T = {
+ val field = clazz.getDeclaredField(name)
+ field.setAccessible(true)
+ val oldValue = field.get(global).asInstanceOf[T]
+ field.set(global, newValue)
+ oldValue
+ }
+
+}
+
+
+trait UsedDepsPhase[G <: Global] {
+ val global: G
+ import global._
+
+ def apply(unit: CompilationUnit): Unit = {
+ val map = traceSymbols.allSymbols.values
+ .filter(_.associatedFile != NoAbstractFile)
+ .filter(_.associatedFile.file != null)
+ .foldLeft(Map.empty[File, List[Symbol]]) { (acc, sym) =>
+ val k = sym.associatedFile.file
+ acc.get(k) match {
+ case Some(vv) => acc + ((k, sym :: vv))
+ case None => acc + ((k, sym :: Nil))
+ }
+ }
+
+ map.foreach { case (k, v) =>
+ println(k)
+ v.foreach(sym => println(" " + sym))
+ }
+
+ ()
+ }
+
+}
diff --git a/src/test/scala/higherkindness/rules_scala/used_deps/BUILD b/src/test/scala/higherkindness/rules_scala/used_deps/BUILD
new file mode 100644
index 000000000..673513659
--- /dev/null
+++ b/src/test/scala/higherkindness/rules_scala/used_deps/BUILD
@@ -0,0 +1,47 @@
+load("//rules:scalafmt.bzl", "scala_format_test")
+load("//rules:scala.bzl", "scala_library")
+
+scala_library(
+ name = "LibA1",
+ srcs = [
+ "LibA1.scala",
+ ],
+ scala = "//external:scala_annex_scala",
+ plugins = [
+ "//src/main/scala/higherkindness/rules_scala/used_deps",
+ ],
+ visibility = ["//visibility:public"],
+)
+
+scala_library(
+ name = "LibA2",
+ srcs = [
+ "LibA2.scala",
+ ],
+ scala = "//external:scala_annex_scala",
+ plugins = [
+ "//src/main/scala/higherkindness/rules_scala/used_deps",
+ ],
+ visibility = ["//visibility:public"],
+)
+
+scala_library(
+ name = "LibB",
+ srcs = [
+ "LibB.scala",
+ ],
+ deps = [
+ ":LibA1",
+ ":LibA2",
+ ],
+ scala = "//external:scala_annex_scala",
+ plugins = [
+ "//src/main/scala/higherkindness/rules_scala/used_deps",
+ ],
+ visibility = ["//visibility:public"],
+)
+
+scala_format_test(
+ name = "format",
+ srcs = glob(["**/*.scala"]),
+)
diff --git a/src/test/scala/higherkindness/rules_scala/used_deps/LibA1.scala b/src/test/scala/higherkindness/rules_scala/used_deps/LibA1.scala
new file mode 100644
index 000000000..769dce933
--- /dev/null
+++ b/src/test/scala/higherkindness/rules_scala/used_deps/LibA1.scala
@@ -0,0 +1,4 @@
+package higherkindness.rules_scala
+package used_deps
+
+trait LibA1
diff --git a/src/test/scala/higherkindness/rules_scala/used_deps/LibA2.scala b/src/test/scala/higherkindness/rules_scala/used_deps/LibA2.scala
new file mode 100644
index 000000000..0c07e941b
--- /dev/null
+++ b/src/test/scala/higherkindness/rules_scala/used_deps/LibA2.scala
@@ -0,0 +1,4 @@
+package higherkindness.rules_scala
+package used_deps
+
+trait LibA2
diff --git a/src/test/scala/higherkindness/rules_scala/used_deps/LibB.scala b/src/test/scala/higherkindness/rules_scala/used_deps/LibB.scala
new file mode 100644
index 000000000..53e38d6ba
--- /dev/null
+++ b/src/test/scala/higherkindness/rules_scala/used_deps/LibB.scala
@@ -0,0 +1,4 @@
+package higherkindness.rules_scala
+package used_deps
+
+trait LibB extends LibA1 with LibA2
diff --git a/src/test/scala/higherkindness/rules_scala/used_deps/test1.scala b/src/test/scala/higherkindness/rules_scala/used_deps/test1.scala
new file mode 100644
index 000000000..66d179a51
--- /dev/null
+++ b/src/test/scala/higherkindness/rules_scala/used_deps/test1.scala
@@ -0,0 +1,6 @@
+package higherkindness.rules_scala
+package test1
+
+class Test1 {
+
+}