问题
Generate companion object for case class with scala-macros
some code example that i tried, it works i can get list of tuple (name -> type) but how to generate the object in the same scope?
import c.universe._
val tpe = weakTypeOf[T]
val fields = tpe.decls.collectFirst {
case m: MethodSymbol if m.isPrimaryConstructor => m
} .get
.paramLists
.head
val extractParams = fields.map { field =>
val name = field.asTerm.name
val fieldName = name.decodedName.toString
val NullaryMethodType(fieldType) = tpe.decl(name).typeSignature
c.Expr[List[(String, String)]](
q"""
($fieldName, ${fieldType.toString})
"""
)
Is it possible to annotate some case class and the generated companion make visible in the same scope?
// test case: defined a class with some fields
@GenerateCompanionWithFields
case class SomeCaseClass(i: Int, b: Byte, c: Char)
goal:
SomeCaseClass.i() // returns Int
SomeCaseClass.b() // returns Byte
SomeCaseClass.c() // returns Char
回答1:
Your code seems to be intended for def macros. But if you want to generate companion you should use macro annotations
import scala.annotation.{StaticAnnotation, compileTimeOnly}
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
object Macros {
@compileTimeOnly("enable macro paradise")
class GenerateCompanionWithFields extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro Macro.impl
}
object Macro {
def impl(c: whitebox.Context)(annottees: c.Tree*): c.Tree = {
import c.universe._
annottees match {
case (cls @ q"$_ class $tpname[..$_] $_(...$paramss) extends { ..$_ } with ..$_ { $_ => ..$_ }") :: Nil =>
val newMethods = paramss.flatten.map {
case q"$_ val $tname: $tpt = $_" =>
q"def $tname(): String = ${tpt.toString}"
}
q"""
$cls
object ${tpname.toTermName} {
..$newMethods
}
"""
}
}
}
}
import Macros._
object App {
@GenerateCompanionWithFields
case class SomeCaseClass(i: Int, b: Byte, c: Char)
}
//Warning:scalac: {
// case class SomeCaseClass extends scala.Product with scala.Serializable {
// <caseaccessor> <paramaccessor> val i: Int = _;
// <caseaccessor> <paramaccessor> val b: Byte = _;
// <caseaccessor> <paramaccessor> val c: Char = _;
// def <init>(i: Int, b: Byte, c: Char) = {
// super.<init>();
// ()
// }
// };
// object SomeCaseClass extends scala.AnyRef {
// def <init>() = {
// super.<init>();
// ()
// };
// def i(): String = "Int";
// def b(): String = "Byte";
// def c(): String = "Char"
// };
// ()
//}
automatically generate case object for case class
来源:https://stackoverflow.com/questions/57740226/generate-companion-object-for-case-class-with-methods-field-method