io.udash.macros.AllValuesMacro.scala Maven / Gradle / Ivy
package io.udash
package macros
import com.avsystem.commons.macros.AbstractMacroCommons
import scala.reflect.macros.blackbox
// Although published within `macros` module, this macro is not intended to be used outside udash-core codebase.
private[udash] class AllValuesMacro(override val c: blackbox.Context) extends AbstractMacroCommons(c) {
import c.universe._
/**
* Accessible members include methods, modules, val/var setters and getters and Java fields.
*/
private def accessibleMembers(tpe: Type): Iterable[TermSymbol] =
tpe.members.collect { case s if s.isPublic && s.isTerm &&
(s.isJava || (!s.asTerm.isVal && !s.asTerm.isVar)) && !s.isImplementationArtifact => s.asTerm
}
/**
* Returns all public members (including inherited ones) evaluating to type `V` (or its subtype) and obtainable from
* provided `obj` by calling a no-arg method.
*/
def ofType[V: WeakTypeTag](obj: Tree): Tree = {
val valueType = weakTypeOf[V]
val names = accessibleMembers(obj.tpe).iterator.filter { s =>
(s.isMethod || s.isModule) &&
s.typeSignature.paramLists.iterator.flatten.isEmpty &&
s.typeSignature.typeParams.isEmpty &&
s.typeSignatureIn(obj.tpe).finalResultType <:< valueType
}.map(_.name.toTermName).toVector
val objName = c.freshName(TermName("obj"))
q"""
val $objName = $obj
$ListObj[$valueType](..${names.map(n => q"$objName.$n")})
"""
}
}