package xsbt
import scala.tools.nsc.{ io, symtab, Phase }
import io.{ AbstractFile, PlainFile, ZipArchive }
import symtab.Flags
import java.io.File
object Dependency {
def name = "xsbt-dependency"
}
final class Dependency(val global: CallbackGlobal) extends LocateClassFile {
import global._
def newPhase(prev: Phase): Phase = new DependencyPhase(prev)
private class DependencyPhase(prev: Phase) extends Phase(prev) {
override def description = "Extracts dependency information"
def name = Dependency.name
def run {
for (unit <- currentRun.units if !unit.isJava) {
val sourceFile = unit.source.file.file
if (global.callback.nameHashing) {
val dependenciesByMemberRef = extractDependenciesByMemberRef(unit)
for (on <- dependenciesByMemberRef)
processDependency(on, inherited = false)
val dependenciesByInheritance = extractDependenciesByInheritance(unit)
for (on <- dependenciesByInheritance)
processDependency(on, inherited = true)
} else {
for (on <- unit.depends) processDependency(on, inherited = false)
for (on <- inheritedDependencies.getOrElse(sourceFile, Nil: Iterable[Symbol])) processDependency(on, inherited = true)
}
def processDependency(on: Symbol, inherited: Boolean) {
def binaryDependency(file: File, className: String) = callback.binaryDependency(file, className, sourceFile, inherited)
val onSource = on.sourceFile
if (onSource == null) {
classFile(on) match {
case Some((f, className, inOutDir)) =>
if (inOutDir && on.isJavaDefined) registerTopLevelSym(on)
f match {
case ze: ZipArchive#Entry => for (zip <- ze.underlyingSource; zipFile <- Option(zip.file)) binaryDependency(zipFile, className)
case pf: PlainFile => binaryDependency(pf.file, className)
case _ => ()
}
case None => ()
}
} else if (onSource.file != sourceFile)
callback.sourceDependency(onSource.file, sourceFile, inherited)
}
}
}
}
private final class CollectTypeTraverser[T](pf: PartialFunction[Type, T]) extends TypeTraverser {
var collected: List[T] = Nil
def traverse(tpe: Type): Unit = {
if (pf.isDefinedAt(tpe))
collected = pf(tpe) :: collected
mapOver(tpe)
}
}
private abstract class extends Traverser {
protected val = collection.mutable.ArrayBuffer.empty[Symbol]
protected def (: Symbol): Unit = depBuf += dep
def : collection.immutable.Set[Symbol] = {
depBuf.toSet - NoSymbol
}
}
private class extends ExtractDependenciesTraverser {
override def (: Tree): Unit = {
tree match {
case Import(, ) =>
selectors.foreach {
case ImportSelector(nme.WILDCARD, _, null, _) =>
case ImportSelector(: Name, _, _, _) =>
def (: Name) = expr.symbol.info.member(name)
addDependency(lookupImported(name.toTermName))
addDependency(lookupImported(name.toTypeName))
}
case : Select =>
addDependency(select.symbol)
case : Ident =>
addDependency(ident.symbol)
case : TypeTree =>
val = new CollectTypeTraverser(
case if !tpe.typeSymbol.isPackage => tpe.typeSymbol
})
typeSymbolCollector.traverse(typeTree.tpe)
val = typeSymbolCollector.collected.toSet
deps.foreach(addDependency)
case Template(, , body) =>
traverseTrees(body)
case MacroExpansionOf() if original != tree =>
this.traverse(original)
case => ()
}
super.traverse(tree)
}
}
private def (: CompilationUnit): collection.immutable.Set[Symbol] = {
val = new ExtractDependenciesByMemberRefTraverser
traverser.traverse(unit.body)
val = traverser.dependencies
dependencies.map(enclosingTopLevelClass)
}
private final def debuglog(msg: => String) {
if (settings.debug.value)
log(msg)
}
private final class extends ExtractDependenciesTraverser {
override def (tree: Tree): Unit = tree match {
case Template(, , body) =>
val = parents.map( => parent.tpe.typeSymbol).toSet
debuglog("Parent type symbols for " + tree.pos + ": " + parentTypeSymbols.map(_.fullName))
parentTypeSymbols.foreach(addDependency)
traverseTrees(body)
case tree => super.traverse(tree)
}
}
private def (: CompilationUnit): collection.immutable.Set[Symbol] = {
val = new ExtractDependenciesByInheritanceTraverser
traverser.traverse(unit.body)
val = traverser.dependencies
dependencies.map(enclosingTopLevelClass)
}
private def enclosingTopLevelClass(sym: Symbol): Symbol =
sym.enclosingTopLevelClass
}