Skip to content
This repository has been archived by the owner on Jun 4, 2024. It is now read-only.

Add prelim macro tracker [WIP] #76

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions rules/scala/macros/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
load("//rules:scala.bzl",
"annex_scala_library",
"annex_scala_binary")

annex_scala_library(
name = "macro-spoor-plugin",
srcs = glob(["**/*.scala"], exclude = ["**/*Test.scala"]),
scala = "@scala_annex_scala_2_12",
deps = [
"@scala_annex_scala_2_12_scala_compiler//jar",
"@scala_annex_scala_2_12_scala_reflect//jar",
],
deps_used_whitelist = [
"@scala_annex_scala_2_12_scala_reflect//jar",
],
resources = ["scalac-plugin.xml"],
visibility = ["//visibility:public"],
)

annex_scala_binary(
name = "macro-spoor-plugin-usage",
srcs = glob(["**/*Test.scala"]),
scala = "@scala_annex_scala_2_12",
plugins = [
":macro-spoor-plugin",
],
deps = [
"@scala_annex_com_lihaoyi_sourcecode_2_12",
],
deps_used_whitelist = [
],
visibility = ["//visibility:public"],
)
59 changes: 59 additions & 0 deletions rules/scala/macros/MacroSpoorPlugin.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package anx

import scala.annotation.tailrec

import scala.tools.nsc.{Global ⇒ NscGlobal}
import scala.tools.nsc.plugins.{Plugin => NscPlugin, PluginComponent => NscPluginComponent}
import scala.reflect.internal.Mode

import scala.reflect.io.NoAbstractFile
import scala.tools.nsc.io.AbstractFile

import java.io.File

final class MacroSpoorPlugin(val global: NscGlobal) extends NscPlugin {
import global._
import analyzer.{MacroPlugin => NscMacroPlugin, _}

override val name: String = "anx-macro-spoor"
override val description: String = "tracks which dependencies are needed to expand macros"
override val components: List[NscPluginComponent] = Nil

analyzer.addMacroPlugin(MacroPlugin)

private[this] object MacroPlugin extends NscMacroPlugin {
override def pluginsMacroRuntime(expandee: Tree): Option[MacroRuntime] = {
val macroDef = expandee.symbol
if (!fastTrack.contains(macroDef)) {
val file = classFile(macroDef.owner)
println("macro used file: " + file)
}
None
}
}

// copied from xsbt.LocateClassFile.classFile
@tailrec private[this] def classFile(sym: Symbol): Option[AbstractFile] = {
if (sym hasFlag scala.tools.nsc.symtab.Flags.PACKAGE) None
else {
val file = sym.associatedFile
if (file == NoAbstractFile) {
if (isTopLevelModule(sym)) {
val linked = sym.companionClass
if (linked == NoSymbol) None
else classFile(linked)
} else None
} else Some(file)
}
}

// copied from xsbt.ClassName.flatName
private[this] def flatname(s: Symbol, separator: Char) =
enteringPhase(currentRun.flattenPhase.next) { s fullName separator }

// copied from xsbt.ClassName.isTopLevelModule
private[this] def isTopLevelModule(sym: Symbol): Boolean =
enteringPhase(currentRun.picklerPhase.next) {
sym.isModuleClass && !sym.isImplClass && !sym.isNestedClass
}
}
8 changes: 8 additions & 0 deletions rules/scala/macros/Test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package doof

object Foo {
def main(args: Array[String]): Unit = {
val line = implicitly[sourcecode.Line]
assert(line.value == 6)
}
}
4 changes: 4 additions & 0 deletions rules/scala/macros/scalac-plugin.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<plugin>
<name>anx-macro-spoor</name>
<classname>anx.MacroSpoorPlugin</classname>
</plugin>
12 changes: 8 additions & 4 deletions rules/scala/private/core.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def runner_common(ctx):
]
compile_classpath = depset(order = "preorder", transitive = macro_classpath + [sdeps.transitive_compile_time_jars])

zipper_inputs, _, zipper_manifests = ctx.resolve_command(tools = [ctx.attr._zipper])
zipper_inputs, _, zipper_manifests = ctx.resolve_command(tools = [ctx.attr._zipper])

if ctx.files.resources:
class_jar = ctx.actions.declare_file("{}/classes.zip".format(ctx.label.name))
Expand All @@ -94,8 +94,9 @@ def runner_common(ctx):
args.add(resource_jar)
args.set_param_file_format("multiline")
args.use_param_file("@%s")
strip_prefix = ctx.label.package + "/" + ctx.attr.resource_strip_prefix
for file in ctx.files.resources:
args.add("{}={}".format(_resource_path(file, ctx.attr.resource_strip_prefix), file.path))
args.add("{}={}".format(_resource_path(file, strip_prefix), file.path))
ctx.actions.run(
arguments = [args],
executable = ctx.executable._zipper,
Expand Down Expand Up @@ -292,10 +293,13 @@ def _labeled_groups(labeled_jars_list):
return [_labeled_group(labeled_jars) for labeled_jars in labeled_jars_list]

def _resource_path(file, strip_prefix):
print(file.short_path)
print(strip_prefix)
if strip_prefix:
if not file.short_path.startswith(strip_prefix):
fail("{} does not have prefix {}".format(file.short_path, strip_prefix))
return file.short_path[len(strip_prefix) + 1 - int(file.short_path.endswith("/")):]
fail("{} does not have prefix {}".format(file.short_path, strip_prefix))
return file.short_path[len(strip_prefix):]
# todo: consider removing custom automatic handling?
conventional = [
"src/main/resources/",
"src/test/resources/",
Expand Down