5

私は 2 つのクラスを持っています。それらFooを と と呼びますFizzFoo一部のメソッドのエイリアスを作成するために呼び出されるアノテーション マクロを使用expandします (実際の実装はエイリアスの作成よりも少し多くのことを行いますが、単純なバージョンでは依然として次の問題が発生します)。簡単にするために、expandマクロが単に注釈付きクラス内のすべてのメソッドを取得し、それらのコピーを作成し、メソッド名の末尾に「Copy」を追加してから、呼び出しを元のメソッドに転送するとします。

私の問題は、expandマクロ onを使用するとFoo、 というメソッドのコピーが作成され、が別のクラス内で呼び出されFoo#barbarCopyときに、すべてがコンパイルされますが、scaladoc の生成は次のように失敗します。barCopyFizz

[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 の両方でこれを試しました。これは、私が抱えている問題を示す単純な sbt プロジェクトです。

4

1 に答える 1