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

izumi.fundamentals.platform.language.SourceFilePositionMaterializer.scala Maven / Gradle / Ivy

package izumi.fundamentals.platform.language

import scala.language.experimental.macros
import scala.reflect.macros.blackbox

final case class SourceFilePositionMaterializer(get: SourceFilePosition) extends AnyVal

object SourceFilePositionMaterializer {
  @inline def sourcePosition(implicit ev: SourceFilePositionMaterializer): SourceFilePosition = ev.get

  implicit def materialize: SourceFilePositionMaterializer = macro SourcePositionMaterializerMacro.getSourceFilePositionMaterializer

  object SourcePositionMaterializerMacro {

    // scalactic.source.Position does all that manually and uses `setType`s to avoid retypechecking, oh well might as well...
    // PS: To ensure that retypechecking does not happen, put a known bad type into `setType` and watch compiler crash.
    //     If it _doesn't_ crash, that means one of the tree nodes was missing a `setType`

    def literal(c: blackbox.Context)(tpe: c.Type)(a: Any): c.universe.Literal = {
      c.internal.setType(c.universe.Literal(c.universe.Constant(a)), tpe)
    }

    def getSourceFilePositionMaterializer(c: blackbox.Context): c.Tree = {
      import c.universe._
      import c.universe.internal._
      import c.universe.internal.gen.{mkAttributedIdent, mkAttributedSelect}

      val sourceFilePosition = getSourceFilePosition(c)

      val matTpe = typeOf[SourceFilePositionMaterializer]
      val matModule = matTpe.companion.typeSymbol.asClass.module

      val sourceFilePositionMaterliazer = Apply(
        mkAttributedSelect(
          mkAttributedIdent(matModule),
          matModule.typeSignature.decl(TermName("apply")),
        ),
        sourceFilePosition :: Nil,
      )
      setType(sourceFilePositionMaterliazer, matTpe)
    }

    def getSourceFilePosition(c: blackbox.Context): c.Tree = {
      import c.universe._
      import c.universe.internal._
      import c.universe.internal.gen.{mkAttributedIdent, mkAttributedSelect}

      val posTpe = typeOf[SourceFilePosition]
      val posModule = posTpe.companion.typeSymbol.asClass.module

      val sourceFilePosition = Apply(
        mkAttributedSelect(
          mkAttributedIdent(posModule),
          posModule.typeSignature.decl(TermName("apply")),
        ),
        literal(c)(definitions.StringClass.toTypeConstructor)(c.enclosingPosition.source.file.name) ::
        literal(c)(definitions.IntTpe)(c.enclosingPosition.line) :: Nil,
      )
      setType(sourceFilePosition, posTpe)
    }

    def getSourceFilePositionValue(c: blackbox.Context): SourceFilePosition = {
      SourceFilePosition(c.enclosingPosition.source.file.name, c.enclosingPosition.line)
    }

  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy