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

org.wartremover.WartremoverPhase.scala Maven / Gradle / Ivy

package org.wartremover

import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Contexts.Context
import dotty.tools.dotc.plugins.PluginPhase
import dotty.tools.dotc.quoted.QuotesCache
import dotty.tools.dotc.typer.TyperPhase
import dotty.tools.dotc.report
import java.util.concurrent.atomic.AtomicBoolean
import scala.quoted.Quotes
import scala.util.control.NonFatal

object WartremoverPhase {
  private[wartremover] def defaultWartremoverPhaseName: String = "wartremover"
  private[wartremover] def defaultRunsAfter: String = TyperPhase.name
}

class WartremoverPhase(
  errorWarts: List[WartTraverser],
  warningWarts: List[WartTraverser],
  loadFailureWarts: List[(String, Throwable)],
  excluded: List[String],
  logLevel: LogLevel,
  initialLog: AtomicBoolean,
  override val runsAfter: Set[String],
  override val phaseName: String
) extends PluginPhase {

  def this(
    errorWarts: List[WartTraverser],
    warningWarts: List[WartTraverser],
    loadFailureWarts: List[(String, Throwable)],
    excluded: List[String],
    logLevel: LogLevel,
    initialLog: AtomicBoolean,
  ) = this(
    errorWarts = errorWarts,
    warningWarts = warningWarts,
    loadFailureWarts = loadFailureWarts,
    excluded = excluded,
    logLevel = logLevel,
    initialLog = initialLog,
    runsAfter = Set(WartremoverPhase.defaultRunsAfter),
    phaseName = WartremoverPhase.defaultWartremoverPhaseName
  )

  override def run(using c: Context): Unit = {
    logLevel match {
      case LogLevel.Info | LogLevel.Debug =>
        if (initialLog.getAndSet(false)) {
          if (errorWarts.nonEmpty) {
            report.echo("error warts = " + errorWarts.map(_.getClass.getName.dropRight(1)).mkString(", "))
          }
          if (warningWarts.nonEmpty) {
            report.echo("warning warts = " + warningWarts.map(_.getClass.getName.dropRight(1)).mkString(", "))
          }
          if (loadFailureWarts.nonEmpty) {
            report.warning(s"load failure warts = " + loadFailureWarts.mkString(", "))
          }
          if (excluded.nonEmpty) {
            report.echo("excluded = " + excluded.mkString(", "))
          }
        }
      case LogLevel.Disable =>
    }
    val skip = excluded.exists(c.source.file.absolute.path.startsWith)
    logLevel match {
      case LogLevel.Info | LogLevel.Disable =>
      case LogLevel.Debug =>
        if (skip) {
          report.echo("skip wartremover " + c.compilationUnit.source.file.toString)
        } else {
          report.echo("run wartremover " + c.compilationUnit.source.file.toString)
        }
    }
    if (!skip) {
      super.run
    }
  }

  override def prepareForUnit(tree: tpd.Tree)(using c: Context): Context = {
    val c2 = QuotesCache.init(c.fresh)
    val q = scala.quoted.runtime.impl.QuotesImpl()(using c2)
    def runWart(w: WartTraverser, onlyWarning: Boolean): Unit = {
      val universe = WartUniverse(
        onlyWarning = onlyWarning,
        logLevel = logLevel,
        quotes = q,
      )
      val traverser = w.apply(universe)
      val t = tree.asInstanceOf[traverser.q.reflect.Tree]
      try {
        traverser.traverseTree(t)(t.symbol)
      } catch {
        case NonFatal(e) =>
          logLevel match {
            case LogLevel.Disable =>
            case LogLevel.Info | LogLevel.Debug =>
              report.warning(e.toString, tree.srcPos)
          }
      }
    }

    errorWarts.foreach(w => runWart(w = w, onlyWarning = false))
    warningWarts.foreach(w => runWart(w = w, onlyWarning = true))
    c
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy