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

izumi.reflect.dottyreflection.FullDbInspector.scala Maven / Gradle / Ivy

There is a newer version: 2.3.10
Show newest version
package izumi.reflect.dottyreflection

import izumi.reflect.internal.fundamentals.collections.IzCollections.toRich
import izumi.reflect.macrortti.LightTypeTagRef
import izumi.reflect.macrortti.LightTypeTagRef._

import scala.collection.mutable
import scala.quoted._

abstract class FullDbInspector(protected val shift: Int) extends InspectorBase {
  self =>

  // @formatter:off
  import qctx.reflect._
  private lazy val inspector = new Inspector(0) { val qctx: FullDbInspector.this.qctx.type = FullDbInspector.this.qctx }
  // @formatter:on

  def buildFullDb[T <: AnyKind: Type]: Map[AbstractReference, Set[AbstractReference]] = {
    val uns = TypeTree.of[T]
    new Run()
      .inspectTreeToFull(uns)
      .toMultimap
      .map {
        case (t, parents) =>
          t -> parents.filterNot(_ == t)
      }
      .filterNot(_._2.isEmpty)
  }

  class Run() {
    private val termination = mutable.HashSet[TypeRepr]()

    def inspectTreeToFull(uns: TypeTree): List[(AbstractReference, AbstractReference)] = {
      val symbol = uns.symbol
      // FIXME: `inspectSymbolToFull` seems unnecessary and lead to bad results after blackbox macros were introduce{d
      if (true) {
        inspectTypeReprToFullBases(uns.tpe).distinct
      } else {
        inspectSymbolToFull(symbol).distinct
      }
    }

    private def inspectTypeReprToFullBases(tpe: TypeRepr): List[(AbstractReference, AbstractReference)] = {
      val selfRef = inspector.inspectTypeRepr(tpe)

      tpe.dealias match {
        case a: AppliedType =>
          val baseTypes = a.baseClasses.map(b => a.baseType(b)).filterNot(termination.contains)
          log(s"For `$tpe` found base types $baseTypes")

          val main = (selfRef, selfRef) +: baseTypes.map {
            bt =>
              val parentRef = inspector.inspectTypeRepr(bt)
              (selfRef, parentRef)
          }

          val args = a.args.filterNot(termination.contains).flatMap {
            x =>
              termination.add(x)
              inspectToBToFull(x)
          }
          (main ++ args).distinct

        case l: TypeLambda =>
          val parents = inspectToBToFull(l.resType)
          val selfL = selfRef.asInstanceOf[LightTypeTagRef.Lambda]
          val out = parents.map {
            case (c, p) =>
              if (c == selfL.output) {
                (selfL, p)
              } else {
                (c, p)
              }
          }
          out.distinct

        case a: AndType =>
          inspectTypeReprToFullBases(a.left) ++ inspectTypeReprToFullBases(a.right)

        case o: OrType =>
          inspectTypeReprToFullBases(o.left) ++ inspectTypeReprToFullBases(o.right)

        case r: TypeRef =>
          inspectSymbolToFull(r.typeSymbol)

        case r: ParamRef =>
          inspectSymbolToFull(r.typeSymbol)

        case b: TypeBounds =>
          inspectToBToFull(b)

        case c: ConstantType =>
          inspectTypeReprToFullBases(c.widen)

        case o =>
          log(s"FullDbInspector: UNSUPPORTED: $o")
          List.empty
      }
    }

    private def inspectSymbolToFull(symbol: Symbol): List[(AbstractReference, AbstractReference)] = {
      symbol.tree match {
        case c: ClassDef =>
//          val parentSymbols = c.parents.map(_.symbol).filterNot(_.isNoSymbol)
          val trees = c.parents.collect { case tt: TypeTree => tt }
          if (trees.nonEmpty) log(s"Found parent trees for symbol ${symbol.tree.show}: $trees")

          val o = trees.flatMap(inspectTreeToFull)
          val selfRef = inspector.inspectSymbolTree(symbol)
          val p = trees.flatMap(t => List((selfRef, inspector.inspectTypeRepr(t.tpe))))
          (p ++ o).distinct

        case t: TypeDef =>
          log(s"FullDbInspector: Found TypeDef symbol ${t.show}")
          inspectTreeToFull(t.rhs.asInstanceOf[TypeTree])

        case o =>
          throw new RuntimeException(s"Shit tree: $o")
          List.empty
      }
    }

    private def inspectToBToFull(tpe: TypeRepr): List[(AbstractReference, AbstractReference)] = {
      tpe.dealias match {
        case t: TypeBounds =>
          inspectTypeReprToFullBases(t.hi) ++ inspectTypeReprToFullBases(t.low)
        case t: TypeRepr =>
          inspectTypeReprToFullBases(t)
      }
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy