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

acyclic.plugin.PluginPhase.scala Maven / Gradle / Ivy

package acyclic.plugin

import acyclic.file
import acyclic.plugin.Compat._
import scala.collection.{SortedSet, mutable}
import scala.tools.nsc.{Global, Phase}
import tools.nsc.plugins.PluginComponent

/**
 * - Break dependency graph into strongly connected components
 * - Turn acyclic packages into virtual "files" in the dependency graph, as
 *   aggregates of all the files within them
 * - Any strongly connected component which includes an acyclic.file or
 *   acyclic.pkg is a failure
 *   - Pick an arbitrary cycle and report it
 * - Don't report more than one cycle per file/pkg, to avoid excessive spam
 */
class PluginPhase(
    val global: Global,
    cycleReporter: Seq[(Value, SortedSet[Int])] => Unit,
    force: => Boolean,
    fatal: => Boolean
) extends PluginComponent { t =>

  import global._

  val runsAfter = List("typer")

  override val runsBefore = List("patmat")

  val phaseName = "acyclic"

  private object base extends BasePluginPhase[CompilationUnit, Tree, Symbol] with GraphAnalysis[Tree] {
    protected val cycleReporter = t.cycleReporter
    protected lazy val force = t.force
    protected lazy val fatal = t.fatal

    def treeLine(tree: Tree): Int = tree.pos.line
    def treeSymbolString(tree: Tree): String = tree.symbol.toString

    def reportError(msg: String): Unit = global.error(msg)
    def reportWarning(msg: String): Unit = global.warning(msg)
    def reportInform(msg: String): Unit = global.inform(msg)
    def reportEcho(msg: String, tree: Tree): Unit = global.reporter.echo(tree.pos, msg)

    def units: Seq[CompilationUnit] = global.currentRun.units.toSeq.sortBy(_.source.content.mkString.hashCode())
    def unitTree(unit: CompilationUnit): Tree = unit.body
    def unitPath(unit: CompilationUnit): String = unit.source.path
    def unitPkgName(unit: CompilationUnit): List[String] =
      unit.body.collect { case x: PackageDef => x.pid.toString }.flatMap(_.split('.'))
    def findPkgObjects(tree: Tree): List[Tree] = tree.collect { case x: ModuleDef if x.name.toString == "package" => x }
    def pkgObjectName(pkgObject: Tree): String = pkgObject.symbol.enclosingPackageClass.fullName
    def hasAcyclicImport(tree: Tree, selector: String): Boolean =
      tree.collect {
        case Import(expr, List(sel)) => expr.symbol.toString == "package acyclic" && sel.name.toString == selector
      }.exists(identity)

    def extractDependencies(unit: CompilationUnit): Seq[(Symbol, Tree)] = DependencyExtraction(global)(unit)
    def symbolPath(sym: Symbol): String = sym.sourceFile.path
    def isValidSymbol(sym: Symbol): Boolean = sym != NoSymbol && sym.sourceFile != null
  }

  override def newPhase(prev: Phase): Phase = new Phase(prev) {
    override def run(): Unit = base.runAllUnits()

    def name: String = "acyclic"
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy