多个scala宏注释不会生成类文件

时间:2016-09-28 07:58:46

标签: scala macros annotations

我在Scala中创建了一个创建伴侣类的注释(如果它还不存在)并在伴侣类中添加了一些方法。 当我有一个注释时它工作正常,但是当我在类上放置两个注释时,不会生成伴随类($ file)的类文件。 此外,在已经有伴随对象的类上有两个注释也可以使用o_O。

以下是我的注释宏:

class Foo extends StaticAnnotation{
  def macroTransform(annottees: Any*): Any = macro Foo.impl
}

object Foo {
  def impl(c: whitebox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._

    def addFooFunctionality(module: Tree): Tree = {
      val fooerType = weakTypeOf[Fooer].typeSymbol

      module match {
        case q"object $className { ..$body }" =>
          q"""
              object $className extends $fooerType {
                ..$body

                val doFoo: String = "Foo"
              }
           """
        case q"object $className extends ..$parents { ..$body }" =>
          q"""
             object $className extends ..$parents with $fooerType {
               ..$body

               val doFoo: String = "Foo"
             }
           """
        case _ => c.abort(c.enclosingPosition, "Module does not match")
      }
    }

    val result = annottees map (_.tree) toList match {
      case (classDef @ ClassDef(cMods, cName, _, _)) :: tail =>
        val moduleDef = tail match {
          case (md @ ModuleDef(_, mName, _)) :: Nil if cName.decodedName.toString == mName.decodedName.toString => md
          case Nil =>
            q"""
             object ${cName.toTermName} {

             }
             """
          case e => c.abort(c.enclosingPosition, s"Foo annotation only works on classes. Not $e.")
        }
        val modifiedModuleDef = addFooFunctionality(moduleDef)

        c.Expr[Fooer](q"""
            $classDef
            $modifiedModuleDef
          """)

      case e => c.abort(c.enclosingPosition, s"Foo annotation only works on classes. Not $e.")
    }

    result
  }
}


trait Fooer {
  val doFoo : String
}

和Bar     class Bar扩展StaticAnnotation {       def macroTransform(annottees:Any *):Any = macro Bar.impl     }

object Bar {
  def impl(c: scala.reflect.macros.whitebox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._

    def addBarFunctionality(module: Tree): Tree = {
      val barerType = weakTypeOf[Barer].typeSymbol

      module match {
        case q"object $className { ..$body }" =>
          q"""
              object $className extends $barerType {
                ..$body

                val doBar: String = "Bar"
              }
           """

        case q"object $className extends ..$parents { ..$body }" =>
          q"""
             object $className extends ..$parents with $barerType {
               ..$body

               val doBar: String = "Bar"
             }
           """
      }
    }

    annottees map (_.tree) toList match {
      case (classDef @ ClassDef(cMods, cName, _, _)) :: tail =>
        val moduleDef = tail match {
          case (md @ ModuleDef(_, mName, _)) :: Nil if cName.decodedName.toString == mName.decodedName.toString => md
          case Nil =>
            q"""
             object ${cName.toTermName} {

             }
             """
          case e => c.abort(c.enclosingPosition, s"Bar annotation only works on classes. Not $e.")
        }
        val modifiedModuleDef = addBarFunctionality(moduleDef)

        c.Expr(q"""
            $classDef
            $modifiedModuleDef
          """)

      case e => c.abort(c.enclosingPosition, s"Bar annotation only works on classes. Not $e.")
    }
  }
}


trait Barer {
  val doBar : String
}

我已经定义了这六个类

@Foo
case class A(name: String)

@Bar
case class B(name: String)

@Foo
@Bar
case class C(name: String)

@Bar
@Foo
case class D(name: String)

@Foo
@Bar
case class E(name: String)
object E {}

@Bar
@Foo
case class F(name: String)
object F {}

当我运行这些测试时

class FooBarTest {

  @Test
  def testA() = {
    val a = A("Hello")

    assertEquals("Hello", a.name)
    assertEquals("Foo", A.doFoo)
  }

  @Test
  def testB() = {
    val b = B("Hello")

    assertEquals("Hello", b.name)
    assertEquals("Bar", B.doBar)
  }

  @Test
  def testC() = {
    val c = C("Hello")

    assertEquals("Hello", c.name)
    assertEquals("Foo", C.doFoo)
    assertEquals("Bar", C.doBar)
  }

  @Test
  def testD() = {
    val d = D("Hello")

    assertEquals("Hello", d.name)
    assertEquals("Foo", D.doFoo)
    assertEquals("Bar", D.doBar)
  }

  @Test
  def testE() = {
    val e = E("Hello")

    assertEquals("Hello", e.name)
    assertEquals("Foo", E.doFoo)
    assertEquals("Bar", E.doBar)
  }

  @Test
  def testF() = {
    val f = F("Hello")

    assertEquals("Hello", f.name)
    assertEquals("Foo", F.doFoo)
    assertEquals("Bar", F.doBar)
  }
}

testAtestBtestEtestF通过。 testCtestD失败

java.lang.NoClassDefFoundError: gizmo/C$

    at gizmo.FooBarTest.testC(FooBarTest.scala:33)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Caused by: java.lang.ClassNotFoundException: gizmo.C$
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 28 more

testD的相同消息。

0 个答案:

没有答案