我可以将类作为宏注释的参数

时间:2016-07-14 13:50:51

标签: scala scala-macros

我试图根据第三方注释预处理器生成的一些java类来构建一个scala类。

我希望能够指出"来自带注释的对象的类,例如:

@MyAnnotation(classOf[GeneratedJavaClass]) object MyObject

@MyAnnotation object MyObject extends PlaceHolderTrait[GeneratedJavaClass]

在实际的宏实现中,我想反思GeneratedJavaClass,找到我用来构建MyObject实现的成员

到目前为止,我的起点基于https://github.com/travisbrown/type-provider-examples/blob/master/rdfs-public/src/main/scala/public/PrefixGenerator.scala

我试图了解如何将Class [T]作为注释的参数,然后在c.macroApplication上与Apply(Select(Apply(_, List(TypeApply(_, List(catalog)))), _), _)匹配,但我得到的类型是{{我没有看到从那里获得课程的方法(我假设classOf [T]不是文字)。

作为替代方案,我想我会尝试从我具有对象扩展的特征中提取我想要的类型。我尝试将annotee与TypeApply(_, List(Trees$Ident)进行匹配,但最后再次使用Trees $ Ident,并且不确定如何获取正在引用的类。

我意识到我可能只是传递完全限定名称的字符串并使用反射来获取类,但我希望有更好的选择。请注意,我并没有指定这两个选项来指定课程,它们只是我能够提出的两个选项。

2 个答案:

答案 0 :(得分:1)

好的,终于根据https://github.com/scalamacros/paradise/issues/69得到了一些有用的东西我意识到在舞台上我没有跑步,因此期望得到一个类型有点傻。宏api确实提供了typeCheck方法,它允许您在树上运行typer,如下所示:

class AnnotationArgument[T] extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro AnnotationArgumentImpl.impl
}

class AnnotationArgumentImpl(val c: blackbox.Context) {

  import c.universe._

  def impl(annottees: c.Expr[Any]*): c.Tree = {
      val macroTypeWithArguments = c.typeCheck(q"${c.prefix.tree}").tpe // my.package.AnnotationArgument[my.package.MyClass]
      val annotationClass: ClassSymbol = macroTypeWithArguments.typeSymbol.asClass // my.package.AnnotationArgument
      val annotationTypePlaceholder: Type = annotationClass.typeParams.head.asType.toType // T
      val argumentType: Type = annotationTypePlaceholder.asSeenFrom(args, annotationClass) // my.package.MyClass

      println(s"the argument's type is $argumentType")


    q"..${annottees}"
  }
}

import my.package.MyClass
@AnnotationArgument[MyClass]
class AnnotationArgumentTestClass

答案 1 :(得分:0)

另一个想法:

使用另一个类注释保存类信息

class AnnotationArgumentClass[T](clazz: Class[T]) extends StaticAnnotation

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

class AnnotationArgumentImpl(val c: blackbox.Context) {

  import c.universe._

  def impl(annottees: c.Expr[Any]*): c.Tree = {
    val classValue = annottees.head.tree match {
      case x: MemberDefApi => x.mods.annotations collectFirst {
        case q"new $annotation($classValue)" => classValue
      }
    }

    /*edit :*/
    val x = (c.eval(c.Expr[Type](c.typecheck(classValue.get))))
    println(x.typeSymbol.fullName)

    q"..${annottees}"
  }
}

测试:

package aaa 
class AAA

//

import aaa.AAA 
@AnnotationArgument
@AnnotationArgumentClass(classOf[AAA])
class AnnotationArgumentTestClass