diff --git a/compile/inc/src/main/scala/sbt/inc/Compile.scala b/compile/inc/src/main/scala/sbt/inc/Compile.scala
index e5dae387c..ce1803ccc 100644
--- a/compile/inc/src/main/scala/sbt/inc/Compile.scala
+++ b/compile/inc/src/main/scala/sbt/inc/Compile.scala
@@ -151,9 +151,6 @@ private final class AnalysisCallback(internalMap: File => Option[File], external
apis(sourceFile) = (HashAPI(source), savedSource)
}
- def endSource(sourcePath: File): Unit =
- assert(apis.contains(sourcePath))
-
def get: Analysis = addCompilation( addExternals( addBinaries( addProducts( addSources(Analysis.Empty) ) ) ) )
def addProducts(base: Analysis): Analysis = addAll(base, classes) { case (a, src, (prod, name)) => a.addProduct(src, prod, current product prod, name ) }
def addBinaries(base: Analysis): Analysis = addAll(base, binaryDeps)( (a, src, bin) => a.addBinaryDep(src, bin, binaryClassName(bin), current binary bin) )
@@ -178,6 +175,4 @@ private final class AnalysisCallback(internalMap: File => Option[File], external
(outer /: bs) { (inner, b) =>
f(inner, a, b)
} }
-
- def beginSource(source: File) {}
}
diff --git a/compile/interface/src/main/scala/xsbt/Analyzer.scala b/compile/interface/src/main/scala/xsbt/Analyzer.scala
index 0f7737305..dd11fe0e0 100644
--- a/compile/interface/src/main/scala/xsbt/Analyzer.scala
+++ b/compile/interface/src/main/scala/xsbt/Analyzer.scala
@@ -23,40 +23,13 @@ final class Analyzer(val global: CallbackGlobal) extends LocateClassFile
def newPhase(prev: Phase): Phase = new AnalyzerPhase(prev)
private class AnalyzerPhase(prev: Phase) extends Phase(prev)
{
- override def description = "Extracts dependency information, finds concrete instances of provided superclasses, and application entry points."
+ override def description = "Finds concrete instances of provided superclasses, and application entry points."
def name = Analyzer.name
def run
{
for(unit <- currentRun.units if !unit.isJava)
{
- // build dependencies structure
val sourceFile = unit.source.file.file
- callback.beginSource(sourceFile)
- 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
- callback.sourceDependency(onSource.file, sourceFile, inherited)
- }
-
// build list of generated classes
for(iclass <- unit.icode)
{
@@ -75,10 +48,8 @@ final class Analyzer(val global: CallbackGlobal) extends LocateClassFile
else
addGenerated(false)
}
- callback.endSource(sourceFile)
}
}
}
-
}
diff --git a/compile/interface/src/main/scala/xsbt/CompilerInterface.scala b/compile/interface/src/main/scala/xsbt/CompilerInterface.scala
index 7f94d1dab..9d1285640 100644
--- a/compile/interface/src/main/scala/xsbt/CompilerInterface.scala
+++ b/compile/interface/src/main/scala/xsbt/CompilerInterface.scala
@@ -176,6 +176,26 @@ private final class CachedCompiler0(args: Array[String], output: Output, initial
def newPhase(prev: Phase) = analyzer.newPhase(prev)
def name = phaseName
}
+
+ /** Phase that extracts dependency information */
+ object sbtDependency extends
+ {
+ val global: Compiler.this.type = Compiler.this
+ val phaseName = Dependency.name
+ val runsAfter = List(API.name)
+ override val runsBefore = List("refchecks")
+ // keep API and dependency close to each other
+ // we might want to merge them in the future and even if don't
+ // do that then it makes sense to run those phases next to each other
+ val runsRightAfter = Some(API.name)
+ }
+ with SubComponent
+ {
+ val dependency = new Dependency(global)
+ def newPhase(prev: Phase) = dependency.newPhase(prev)
+ def name = phaseName
+ }
+
/** This phase walks trees and constructs a representation of the public API, which is used for incremental recompilation.
*
* We extract the api after picklers, since that way we see the same symbol information/structure
@@ -202,6 +222,7 @@ private final class CachedCompiler0(args: Array[String], output: Output, initial
override lazy val phaseDescriptors =
{
phasesSet += sbtAnalyzer
+ phasesSet += sbtDependency
phasesSet += apiExtractor
superComputePhaseDescriptors
}
@@ -221,7 +242,7 @@ private final class CachedCompiler0(args: Array[String], output: Output, initial
for( (what, warnings) <- seq; (pos, msg) <- warnings) yield
callback.problem(what, drep.convert(pos), msg, Severity.Warn, false)
}
-
+
def set(callback: AnalysisCallback, dreporter: DelegatingReporter)
{
this.callback0 = callback
diff --git a/compile/interface/src/main/scala/xsbt/Dependency.scala b/compile/interface/src/main/scala/xsbt/Dependency.scala
new file mode 100644
index 000000000..8035574e6
--- /dev/null
+++ b/compile/interface/src/main/scala/xsbt/Dependency.scala
@@ -0,0 +1,74 @@
+/* sbt -- Simple Build Tool
+ * Copyright 2008, 2009 Mark Harrah
+ */
+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"
+}
+/**
+ * Extracts dependency information from each compilation unit.
+ *
+ * This phase uses CompilationUnit.depends and CallbackGlobal.inheritedDependencies
+ * to collect all symbols that given compilation unit depends on. Those symbols are
+ * guaranteed to represent Class-like structures.
+ *
+ * The CallbackGlobal.inheritedDependencies is populated by the API phase. See,
+ * ExtractAPI class.
+ *
+ * When dependency symbol is processed, it is mapped back to either source file where
+ * it's defined in (if it's available in current compilation run) or classpath entry
+ * where it originates from. The Symbol->Classfile mapping is implemented by
+ * LocateClassFile that we inherit from.
+ */
+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)
+ {
+ // build dependencies structure
+ val sourceFile = unit.source.file.file
+ 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
+ callback.sourceDependency(onSource.file, sourceFile, inherited)
+ }
+ }
+ }
+ }
+
+}
diff --git a/interface/src/main/java/xsbti/AnalysisCallback.java b/interface/src/main/java/xsbti/AnalysisCallback.java
index d00f5b7ed..55a90f011 100644
--- a/interface/src/main/java/xsbti/AnalysisCallback.java
+++ b/interface/src/main/java/xsbti/AnalysisCallback.java
@@ -7,8 +7,6 @@ import java.io.File;
public interface AnalysisCallback
{
- /** Called before the source at the given location is processed. */
- public void beginSource(File source);
/** Called to indicate that the source file source depends on the source file
* dependsOn. Note that only source files included in the current compilation will
* passed to this method. Dependencies on classes generated by sources not in the current compilation will
@@ -24,8 +22,6 @@ public interface AnalysisCallback
/** Called to indicate that the source file source produces a class file at
* module contain class name.*/
public void generatedClass(File source, File module, String name);
- /** Called after the source at the given location has been processed. */
- public void endSource(File sourcePath);
/** Called when the public API of a source file is extracted. */
public void api(File sourceFile, xsbti.api.SourceAPI source);
/** Provides problems discovered during compilation. These may be reported (logged) or unreported.
diff --git a/interface/src/test/scala/TestCallback.scala b/interface/src/test/scala/TestCallback.scala
index 061457723..5c0de068e 100644
--- a/interface/src/test/scala/TestCallback.scala
+++ b/interface/src/test/scala/TestCallback.scala
@@ -5,20 +5,15 @@ package xsbti
class TestCallback extends AnalysisCallback
{
- val beganSources = new ArrayBuffer[File]
- val endedSources = new ArrayBuffer[File]
val sourceDependencies = new ArrayBuffer[(File, File, Boolean)]
val binaryDependencies = new ArrayBuffer[(File, String, File, Boolean)]
val products = new ArrayBuffer[(File, File, String)]
val apis = new ArrayBuffer[(File, xsbti.api.SourceAPI)]
- def beginSource(source: File) { beganSources += source }
-
def sourceDependency(dependsOn: File, source: File, inherited: Boolean) { sourceDependencies += ((dependsOn, source, inherited)) }
def binaryDependency(binary: File, name: String, source: File, inherited: Boolean) { binaryDependencies += ((binary, name, source, inherited)) }
def generatedClass(source: File, module: File, name: String) { products += ((source, module, name)) }
- def endSource(source: File) { endedSources += source }
def api(source: File, sourceAPI: xsbti.api.SourceAPI) { apis += ((source, sourceAPI)) }
def problem(category: String, pos: xsbti.Position, message: String, severity: xsbti.Severity, reported: Boolean) {}
-}
\ No newline at end of file
+}
diff --git a/util/classfile/src/main/scala/sbt/classfile/Analyze.scala b/util/classfile/src/main/scala/sbt/classfile/Analyze.scala
index 117b718ae..724eb1a1e 100644
--- a/util/classfile/src/main/scala/sbt/classfile/Analyze.scala
+++ b/util/classfile/src/main/scala/sbt/classfile/Analyze.scala
@@ -33,12 +33,11 @@ private[sbt] object Analyze
sourceFile <- classFile.sourceFile orElse guessSourceName(newClass.getName);
source <- guessSourcePath(sourceMap, classFile, log))
{
- analysis.beginSource(source)
analysis.generatedClass(source, newClass, classFile.className)
productToSource(newClass) = source
sourceToClassFiles.getOrElseUpdate(source, new ArrayBuffer[ClassFile]) += classFile
}
-
+
// get class to class dependencies and map back to source to class dependencies
for( (source, classFiles) <- sourceToClassFiles )
{
@@ -65,17 +64,14 @@ private[sbt] object Analyze
}
}
def processDependencies(tpes: Iterable[String], inherited: Boolean): Unit = tpes.foreach(tpe => processDependency(tpe, inherited))
-
+
val notInherited = classFiles.flatMap(_.types).toSet -- publicInherited
processDependencies(notInherited, false)
processDependencies(publicInherited, true)
- analysis.endSource(source)
}
for( source <- sources filterNot sourceToClassFiles.keySet ) {
- analysis.beginSource(source)
analysis.api(source, new xsbti.api.SourceAPI(Array(), Array()))
- analysis.endSource(source)
}
}
private[this] def urlAsFile(url: URL, log: Logger): Option[File] =
@@ -114,7 +110,7 @@ private[sbt] object Analyze
}
private def findSource(sourceNameMap: Map[String, Iterable[File]], pkg: List[String], sourceFileName: String): List[File] =
refine( (sourceNameMap get sourceFileName).toList.flatten.map { x => (x,x.getParentFile) }, pkg.reverse)
-
+
@tailrec private def refine(sources: List[(File, File)], pkgRev: List[String]): List[File] =
{
def make = sources.map(_._1)
@@ -155,7 +151,7 @@ private[sbt] object Analyze
method.getReturnType == unit &&
method.getParameterTypes.toList == strArray
private def isMain(modifiers: Int): Boolean = (modifiers & mainModifiers) == mainModifiers && (modifiers & notMainModifiers) == 0
-
+
private val mainModifiers = STATIC | PUBLIC
private val notMainModifiers = ABSTRACT
}