1

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?

Jasper-M
  • 14,966
  • 2
  • 26
  • 37

1 Answers1

2

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.

dveim
  • 3,381
  • 2
  • 21
  • 31
  • If I find a method call in a `Tree`, how can I check that the method which is called has a certain annotation? – Jasper-M Sep 01 '16 at 12:38
  • 1
    `mods` will contain it. http://docs.scala-lang.org/overviews/quasiquotes/definition-details might be useful. – dveim Sep 01 '16 at 12:47
  • 1
    Okay, an alternative that works for me: `methodCallFromTree.symbol.asMethod.annotations`. – Jasper-M Sep 01 '16 at 13:01