【发布时间】:2016-10-26 19:16:57
【问题描述】:
一个非常简单的宏兼容支持宏注释。
def impl(c: blackbox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
annottees.map(_.tree) match {
case (classDef @ q"$mods class $tpname[..$tparams] $ctorMods(...$params) extends { ..$earlydefns } with ..$parents { $self => ..$stats }")
:: Nil if mods.hasFlag(Flag.CASE) =>
val name = tpname.toTermName
val typeName = tpname.toTypeName
val res = q"""
$classDef
object $name {
..${doStuff(c)(typeName, name, params.head)}
}
"""
c.Expr[Any](res)
case _ => c.abort(c.enclosingPosition, "Invalid annotation target, this must be a case class")
}
}
所以一切都非常简单直接有趣。导致问题的位来自上面的$params,它们只是List[List[ValDef]],即不知何故类型签名丢失了。
def accessors(c: blackbox.Context)(
params: Seq[c.universe.ValDef]
): Iterable[(c.universe.TermName, c.universe.TypeName)] = {
import c.universe._
params.map {
case ValDef(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree) => {
// tpt.tpe = kaboom, null pointer
name -> TypeName(tpt.tpe.typeSymbol.fullName)
}
}
}
ValDef 上的tpe 以null 的形式返回,因此没有键入定义,但我需要参数的类型签名来实现我想要的。如何在不爆炸的情况下获得参数的类型签名?
具有讽刺意味的是,showCode(tpt) 确实生成了正确的类型字符串,因此可以使用 TypeName(tpt.toString) 解决此问题,但我不确定为什么无法访问 tpe。
【问题讨论】:
-
你可能想看看 Eugene Burmako 在这个问题中的答案和 cmets:stackoverflow.com/questions/23671379/…