我不确定您到底尝试了什么,但乍一看似乎您至少缺少两部分:您需要使用 aTraverser
遍历树的所有后代,并且需要对每个候选树进行类型检查以确保它被脱糖到你可以告诉你有一个SeqFactory
.
例如,这是一个在编译时打印类中所有序列创建树的快速实现:
import scala.language.experimental.macros
import scala.reflect.macros.Context
object SeqSearch {
def printCreatesInClass = macro printCreatesInClass_impl
def printCreatesInClass_impl(c: Context) = {
import c.universe._
import scala.collection.generic.SeqFactory
val factorySym = c.typeOf[SeqFactory[Seq]].typeSymbol
def isCreation(tree: Tree) = c.typeCheck(tree) match {
case Apply(TypeApply(Select(factory, name), _), _) if
factory.tpe.baseClasses.contains(factorySym) &&
name == newTermName("apply") => true
case _ => false
}
object printCreates extends Traverser {
override def traverse(tree: Tree) = tree match {
case application @ Apply(_, args) if isCreation(application) =>
println("Matched create: " + application)
super.traverseTrees(args)
case _ => super.traverse(tree)
}
}
printCreates(c.enclosingClass)
c.literalUnit
}
}
它是这样工作的:
scala> class Foo {
| SeqSearch.printCreatesInClass
| val l = List(1, 2)
| val v = Vector(1, 2)
| val ab = collection.mutable.ArrayBuffer(1, 2)
| val s = Seq(1, 2)
| }
Matched create: List(1, 2)
Matched create: Vector(1, 2)
Matched create: collection.mutable.ArrayBuffer(1, 2)
Matched create: Seq(1, 2)
defined class Foo
查找访问是类似的——只需将以下方法添加到上面的对象中:
def printAccessesInClass = macro printAccessesInClass_impl
def printAccessesInClass_impl(c: Context) = {
import c.universe._
def isAccess(tree: Tree) = c.typeCheck(tree) match {
case Apply(Select(seq, name), _) if
seq.tpe <:< typeOf[Seq[Any]] &&
name == newTermName("apply") => true
case _ => false
}
object printAccesses extends Traverser {
override def traverse(tree: Tree) = tree match {
case application @ Apply(_, args) if isAccess(application) =>
println("Matched access: " + application)
super.traverseTrees(args)
case _ => super.traverse(tree)
}
}
printAccesses(c.enclosingClass)
c.literalUnit
}
接着:
scala> class Foo {
| SeqSearch.printCreatesInClass
| SeqSearch.printAccessesInClass
| val xs = List(1, 2, 3)
| val xh = xs(0)
| }
Matched create: List(1, 2, 3)
Matched access: xs(0)
defined class Foo
调整 的副作用Traverser
以捕获您感兴趣的任何信息应该很容易,而不仅仅是在编译时打印树。