【发布时间】:2020-06-07 08:37:09
【问题描述】:
我有两个班级,分别叫它们Foo 和Fizz。 Foo 使用一个名为 expand 的注释宏来为其某些方法创建别名(实际实现比创建别名要多一点,但简单的版本仍然存在以下问题)。为简单起见,假设expand 宏简单地获取注释类中的所有方法,并复制它们,将“Copy”附加到方法名称的末尾,然后将调用转发给原始方法。
我的问题是,如果我在 Foo 上使用 expand 宏,它会创建一个名为 barCopy 的方法 Foo#bar 的副本,当在另一个类 Fizz 中调用 barCopy 时,一切编译但 scaladoc 生成失败,如下所示:
[error] ../src/main/scala/Foo.scala:11: value barCopy is not a member of Foo
[error] def str = foo.barCopy("hey")
[error] ^
[info] No documentation generated with unsuccessful compiler run
如果我删除标记正在复制的方法的 scaladoc (Foo#bar),sbt doc 命令将再次起作用。就好像 scaladoc 生成器在不使用已启用的宏天堂插件的情况下调用编译器的早期阶段,但如果从有问题的方法中删除文档,它会以某种方式工作。
这是expand 宏:
import scala.annotation.{ StaticAnnotation, compileTimeOnly }
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
@compileTimeOnly("You must enable the macro paradise plugin.")
class expand extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro Impl.impl
}
object Impl {
def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
val result = annottees map (_.tree) match {
case (classDef @
q"""
$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents {
$self => ..$stats
}
""") :: _ =>
val copies = for {
q"def $tname[..$tparams](...$paramss): $tpt = $expr" <- stats
ident = TermName(tname.toString + "Copy")
} yield {
val paramSymbols = paramss.map(_.map(_.name))
q"def $ident[..$tparams](...$paramss): $tpt = $tname(...$paramSymbols)"
}
q"""
$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self =>
..$stats
..$copies
}
"""
case _ => c.abort(c.enclosingPosition, "Invalid annotation target: not a class")
}
c.Expr[Any](result)
}
}
以及存在于单独项目中的类:
/** This is a class that will have some methods copied. */
@expand class Foo {
/** Remove this scaladoc comment, and `sbt doc` will run just fine! */
def bar(value: String) = value
}
/** Another class. */
class Fizz(foo: Foo) {
/** More scaladoc, nothing wrong here. */
def str = foo.barCopy("hey")
}
这似乎是一个错误,或者可能是一个缺失的功能,但是有没有一种方法可以为上述类生成 scaladoc 而无需从复制的方法中删除文档?我在 Scala 2.11.8 和 2.12.1 上都试过了。 This 是一个简单的 sbt 项目,它演示了我遇到的问题。
【问题讨论】:
标签: scala scala-macros scaladoc scala-macro-paradise