I have a macro and part of that macro consists of replacing every call to a certain method with something else. To accomplish this I use a Transformer
and try to match every Tree
that enters the transform
method against a quasiquote. When I write it like below, it seems to work.
package mypackage
object myobject {
implicit def mymethod[T](t: Option[T]): T = ???
}
object Macros {
import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
def myMacro(c: Context)(expr: c.Tree): c.Tree = {
import c.universe._
val transformer = new Transformer {
private def doSomething(value: c.Tree): TermName = {
???
}
override def transform(tree: c.Tree) = tree match {
case q"mypackage.myobject.mymethod[..$_]($value)" =>
val result = doSomething(value)
q"$result"
case _ => super.transform(tree)
}
}
val transformed = transformer.transform(expr)
???
}
}
But I thought you should always use fully qualified names in macros or you could get into trouble. So I wrote it like q"_root_.mypackage.myobject.mymethod[..$_]($value)"
, but then it no longer matched and the calls to mymethod
no longer got replaced.
I also looked at the suggestion in the scala docs to unquote symbols, but I couldn't get that to work either.
So my question is: will this code (with q"mypackage.myobject.mymethod[..$_]($value)"
) always replace all the calls to mymethod
and never replace any other method calls? And if not, how can I make it more robust?
scala.reflect macros are non hygienic, so, theoretically, q"mypackage.myobject.mymethod[..$_]($value)"
could be matched by someone else.
I'd suggest match that method with q"..$mods def $name[..$tparams](...$paramss): $tpeopt = $expr"
(assuming that is definition, not declaration). You can add checks on name
.
Another solution is to mark method with annotation, and remove it in macro phase.