All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.softwaremill.macwire.internals.CompanionCrimper.scala Maven / Gradle / Ivy

package com.softwaremill.macwire.internals

import scala.quoted.*

private[macwire] class CompanionCrimper[Q <: Quotes, T: Type](using val q: Q)(
    dependencyResolver: DependencyResolver[q.type, T],
    log: Logger
) {
  import q.reflect.*

  lazy val targetType = TypeRepr.of[T]

  lazy val companionType: Option[Symbol] = targetType.typeSymbol.companionClass match {
    case c if c == Symbol.noSymbol => None
    case c                         => Some(c)
  }

  def returnType(symbol: Symbol): TypeRepr = symbol.tree match {
    case dd: DefDef => dd.returnTpt.tpe
  }

  def isCompanionApply(method: Symbol): Boolean =
    method.isDefDef &&
      !(method.flags is Flags.Private) &&
      !(method.flags is Flags.Protected) &&
      returnType(method) <:< targetType &&
      method.name == "apply"

  lazy val applies: Option[List[Symbol]] = log.withBlock("Looking for apply methods of Companion Object") {
    val as: Option[List[Symbol]] = companionType.map(_.declarations.filter(isCompanionApply).toList)

    as.foreach(x => log.withBlock(s"There are ${x.size} apply methods:") { x.foreach(c => log(showApply(c))) })
    as
  }

  lazy val apply: Option[Symbol] = applies.flatMap(_ match {
    case applyMethod :: Nil => Some(applyMethod)
    case _                  => None
  })

  lazy val applySelect: Option[Select] = apply.map(a => Select(Ref(targetType.typeSymbol.companionModule), a))

  lazy val applyParamLists: Option[List[List[Symbol]]] = apply.map(_.paramSymss)

  def wireParams(paramLists: List[List[Symbol]]): List[List[Term]] =
    paramLists.map(_.map(p => dependencyResolver.resolve(p, paramType(p))))

  lazy val applyArgs: Option[List[List[Term]]] = applyParamLists.map(wireParams)

  lazy val applyTree: Option[Tree] = for {
    pl: List[List[Term]] <- applyArgs
    applyMethod: Term <- applySelect
  } yield pl.foldLeft(applyMethod)((acc: Term, args: List[Term]) => Apply(acc, args))

  private def paramType(param: Symbol): TypeRepr = {
    //FIXME
    Ref(param).tpe.widen
  }

  def showApply(c: Symbol): String = c.toString
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy