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

zio.internal.stacktracer.Macros.scala Maven / Gradle / Ivy

package zio.internal.stacktracer

import scala.reflect.macros.{blackbox, whitebox}
import zio.internal.stacktracer.Tracer.createTrace
import zio.stacktracer.DisableAutoTrace

object Macros {

  def sourceLocation(c: blackbox.Context): c.Tree = {
    import c.universe._
    val pos = c.macroApplication.pos
    q"""
      _root_.zio.internal.stacktracer.SourceLocation(
        path = ${pos.source.file.path},
        line = ${pos.line}
      )
    """
  }

  def traceInfo(c: blackbox.Context): String = {

    val location = {
      def loop(current: c.Symbol, acc: List[String] = Nil): List[String] = {
        val currentName = current.name.decodedName.toString.trim
        if (currentName != "")
          loop(current.owner, if (currentName == "$anonfun") acc else currentName :: acc)
        else acc
      }

      loop(c.internal.enclosingOwner).mkString(".")
    }

    val pos  = c.enclosingPosition
    val file = pos.source.file.name
    val line = pos.line
    createTrace(location, file, line)
  }

  def newTraceImpl(c: blackbox.Context): c.Expr[Tracer.instance.Type with zio.internal.stacktracer.Tracer.Traced] =
    traceExpr(traceInfo(c), c)

  def autoTraceImpl(c: whitebox.Context): c.Expr[Tracer.instance.Type with zio.internal.stacktracer.Tracer.Traced] = {
    import c.universe._

    val disableAutoTrace =
      c.inferImplicitValue(weakTypeOf[DisableAutoTrace]) != EmptyTree

    val implicitTraceInScope =
      c.inferImplicitValue(weakTypeOf[Tracer.instance.Type], withMacrosDisabled = true) != EmptyTree

    val traceExpression = traceExpr(traceInfo(c), c)

    if (!disableAutoTrace) {
      if (implicitTraceInScope)
        c.abort(c.enclosingPosition, "we already have an implicit trace - pass it through")
      else //there's no implicit, so generate one
        traceExpression
    } else {
      println(
        s"""[${Console.RED}error${Console.RESET}] ${traceInfo(c)}
           |[${Console.RED}error${Console.RESET}]  
           |[${Console.RED}error${Console.RESET}]  No automatically generated traces are permitted here. Add an implicit parameter
           |[${Console.RED}error${Console.RESET}]  to pass through a user generated trace or explicitly call `newTrace`
           |[${Console.RED}error${Console.RESET}]  to force generation of a new trace.
           |[${Console.RED}error${Console.RESET}]  
           |[${Console.RED}error${Console.RESET}]  copy/paste:
           |[${Console.RED}error${Console.RESET}]    (implicit trace: Trace)  <- no existing implicit parameter list
           |[${Console.RED}error${Console.RESET}]    , trace: Trace           <- existing implicit parameter list
           |[${Console.RED}error${Console.RESET}]    (newTrace)                       <- I know what I'm doing, generate a new trace anyway
           |[${Console.RED}error${Console.RESET}]    
           |""".stripMargin
      )
      c.abort(c.enclosingPosition, "Auto-generated traces are disabled")
    }

  }

  private def traceExpr(trace: String, c: blackbox.Context): c.Expr[Tracer.instance.Type with Tracer.Traced] = {
    import c.universe._
    c.Expr[Tracer.instance.Type with Tracer.Traced](
      q"""$trace.asInstanceOf[_root_.zio.internal.stacktracer.Tracer.instance.Type with _root_.zio.internal.stacktracer.Tracer.Traced]"""
    )
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy