diff --git a/compile/inc/src/main/scala/sbt/inc/Analysis.scala b/compile/inc/src/main/scala/sbt/inc/Analysis.scala
index 90e8c73fa..d9a9dee26 100644
--- a/compile/inc/src/main/scala/sbt/inc/Analysis.scala
+++ b/compile/inc/src/main/scala/sbt/inc/Analysis.scala
@@ -5,6 +5,7 @@ package sbt
package inc
import xsbti.api.Source
+import xsbti.DependencyContext._
import java.io.File
/**
diff --git a/compile/inc/src/main/scala/sbt/inc/Compile.scala b/compile/inc/src/main/scala/sbt/inc/Compile.scala
index dd2dc4223..29fccb034 100644
--- a/compile/inc/src/main/scala/sbt/inc/Compile.scala
+++ b/compile/inc/src/main/scala/sbt/inc/Compile.scala
@@ -10,6 +10,8 @@ import xsbti.{ Position, Problem, Severity }
import Logger.{ m2o, problem }
import java.io.File
import xsbti.api.Definition
+import xsbti.DependencyContext
+import xsbti.DependencyContext.{ DependencyByInheritance, DependencyByMemberRef }
object IncrementalCompile {
def apply(sources: Set[File], entry: String => Option[File],
@@ -61,7 +63,7 @@ private final class AnalysisCallback(internalMap: File => Option[File], external
new Compilation(System.currentTimeMillis, outputSettings)
}
- override def toString = (List("APIs", "Binary deps", "Products", "Source deps") zip List(apis, binaryDeps, classes, sourceDeps)).map { case (label, map) => label + "\n\t" + map.mkString("\n\t") }.mkString("\n")
+ override def toString = (List("APIs", "Binary deps", "Products", "Source deps") zip List(apis, binaryDeps, classes, intSrcDeps)).map { case (label, map) => label + "\n\t" + map.mkString("\n\t") }.mkString("\n")
import collection.mutable.{ HashMap, HashSet, ListBuffer, Map, Set }
@@ -75,12 +77,10 @@ private final class AnalysisCallback(internalMap: File => Option[File], external
private[this] val classes = new HashMap[File, Set[(File, String)]]
// generated class file to its source file
private[this] val classToSource = new HashMap[File, File]
- // all internal source depenencies, including direct and inherited
- private[this] val sourceDeps = new HashMap[File, Set[File]]
- // inherited internal source dependencies
- private[this] val inheritedSourceDeps = new HashMap[File, Set[File]]
+ // internal source dependencies
+ private[this] val intSrcDeps = new HashMap[File, Set[InternalDependency]]
// external source dependencies
- private[this] val extSrcDeps = new HashMap[File, Iterable[ExternalDependency]]
+ private[this] val extSrcDeps = new HashMap[File, Set[ExternalDependency]]
private[this] val binaryClassName = new HashMap[File, String]
// source files containing a macro def.
private[this] val macroSources = Set[File]()
@@ -96,46 +96,57 @@ private final class AnalysisCallback(internalMap: File => Option[File], external
}
}
+ def sourceDependency(dependsOn: File, source: File, context: DependencyContext) = {
+ add(intSrcDeps, source, InternalDependency(source, dependsOn, context))
+ }
+
+ @deprecated("Use `sourceDependency(File, File, DependencyContext)`.", "0.13.8")
def sourceDependency(dependsOn: File, source: File, inherited: Boolean) =
{
- add(sourceDeps, source, dependsOn)
- if (inherited) add(inheritedSourceDeps, source, dependsOn)
+ val context = if (inherited) DependencyByInheritance else DependencyByMemberRef
+ sourceDependency(dependsOn, source, context)
}
- def externalBinaryDependency(binary: File, className: String, source: File, inherited: Boolean) {
+
+ private[this] def externalBinaryDependency(binary: File, className: String, source: File, context: DependencyContext) = {
binaryClassName.put(binary, className)
add(binaryDeps, source, binary)
}
- // The type corresponds to : (internal source, external source depended on, API of external dependency, true if an inheritance dependency)
- def externalSourceDependency(t4: (File, String, Source, Boolean)) = {
- val dependency = ExternalDependency(t4._1, t4._2, t4._3, if (t4._4) DependencyByInheritance else DependencyByMemberRef)
- extSrcDeps += t4._1 -> (extSrcDeps.getOrElse(t4._1, Nil) ++ List(dependency))
+ private[this] def externalSourceDependency(sourceFile: File, dependsOn: String, source: Source, context: DependencyContext) = {
+ val dependency = ExternalDependency(sourceFile, dependsOn, source, context)
+ add(extSrcDeps, sourceFile, dependency)
}
- def binaryDependency(classFile: File, name: String, source: File, inherited: Boolean) =
+ def binaryDependency(classFile: File, name: String, source: File, context: DependencyContext) =
internalMap(classFile) match {
case Some(dependsOn) =>
// dependency is a product of a source not included in this compilation
- sourceDependency(dependsOn, source, inherited)
+ sourceDependency(dependsOn, source, context)
case None =>
classToSource.get(classFile) match {
case Some(dependsOn) =>
// dependency is a product of a source in this compilation step,
// but not in the same compiler run (as in javac v. scalac)
- sourceDependency(dependsOn, source, inherited)
+ sourceDependency(dependsOn, source, context)
case None =>
- externalDependency(classFile, name, source, inherited)
+ externalDependency(classFile, name, source, context)
}
}
- private[this] def externalDependency(classFile: File, name: String, source: File, inherited: Boolean): Unit =
+ @deprecated("Use `binaryDependency(File, String, File, DependencyContext)`.", "0.13.8")
+ def binaryDependency(classFile: File, name: String, source: File, inherited: Boolean) = {
+ val context = if (inherited) DependencyByInheritance else DependencyByMemberRef
+ binaryDependency(classFile, name, source, context)
+ }
+
+ private[this] def externalDependency(classFile: File, name: String, source: File, context: DependencyContext): Unit =
externalAPI(classFile, name) match {
case Some(api) =>
// dependency is a product of a source in another project
- externalSourceDependency((source, name, api, inherited))
+ externalSourceDependency(source, name, api, context)
case None =>
// dependency is some other binary on the classpath
- externalBinaryDependency(classFile, name, source, inherited)
+ externalBinaryDependency(classFile, name, source, context)
}
def generatedClass(source: File, module: File, name: String) =
@@ -174,16 +185,6 @@ private final class AnalysisCallback(internalMap: File => Option[File], external
(a /: names) { case (a, name) => a.copy(relations = a.relations.addUsedName(src, name)) }
}
- // This is no longer used by the new implementation relative to Dependency contexts
- // See https://github.com/sbt/sbt/issues/1340
- def addAll[A, B](base: Analysis, m: Map[A, Set[B]])(f: (Analysis, A, B) => Analysis): Analysis =
- (base /: m) {
- case (outer, (a, bs)) =>
- (outer /: bs) { (inner, b) =>
- f(inner, a, b)
- }
- }
-
def addProductsAndDeps(base: Analysis): Analysis =
(base /: apis) {
case (a, (src, api)) =>
@@ -193,14 +194,12 @@ private final class AnalysisCallback(internalMap: File => Option[File], external
val hasMacro: Boolean = macroSources.contains(src)
val s = new xsbti.api.Source(compilation, hash, api._2, api._1, publicNameHashes(src), hasMacro)
val info = SourceInfos.makeInfo(getOrNil(reporteds, src), getOrNil(unreporteds, src))
- val direct = sourceDeps.getOrElse(src, Nil: Iterable[File])
- val publicInherited = inheritedSourceDeps.getOrElse(src, Nil: Iterable[File])
val binaries = binaryDeps.getOrElse(src, Nil: Iterable[File])
val prods = classes.getOrElse(src, Nil: Iterable[(File, String)])
val products = prods.map { case (prod, name) => (prod, name, current product prod) }
- val internalDeps = direct.map(InternalDependency(src, _, DependencyByMemberRef)) ++ publicInherited.map(InternalDependency(src, _, DependencyByInheritance))
- val externalDeps = extSrcDeps.getOrElse(src, Nil: Iterable[ExternalDependency])
+ val internalDeps = intSrcDeps.getOrElse(src, Set.empty)
+ val externalDeps = extSrcDeps.getOrElse(src, Set.empty)
val binDeps = binaries.map(d => (d, binaryClassName(d), current binary d))
a.addSource(src, s, stamp, info, products, internalDeps, externalDeps, binDeps)
diff --git a/compile/inc/src/main/scala/sbt/inc/Dependency.scala b/compile/inc/src/main/scala/sbt/inc/Dependency.scala
index a10d33d00..668c687fd 100644
--- a/compile/inc/src/main/scala/sbt/inc/Dependency.scala
+++ b/compile/inc/src/main/scala/sbt/inc/Dependency.scala
@@ -2,22 +2,7 @@ package sbt.inc
import java.io.File
import xsbti.api.Source
-
-/**
- * Represents contextual information about particular depedency edge. See comments in
- * subtypes for examples of particular contexts.
- */
-private[inc] sealed abstract class DependencyContext
-
-/**
- * Marks dependency edge introduced by referring to a class through inheritance as in
- *
- * class A extends B
- *
- * Each dependency by inheritance introduces corresponding dependency by member reference.
- */
-private[inc] final case object DependencyByInheritance extends DependencyContext
-private[inc] final case object DependencyByMemberRef extends DependencyContext
+import xsbti.DependencyContext
/**
* Represents the kind of dependency that exists between `sourceFile` and either `targetFile`
diff --git a/compile/inc/src/main/scala/sbt/inc/Relations.scala b/compile/inc/src/main/scala/sbt/inc/Relations.scala
index 5db719311..6f7aaaf82 100644
--- a/compile/inc/src/main/scala/sbt/inc/Relations.scala
+++ b/compile/inc/src/main/scala/sbt/inc/Relations.scala
@@ -8,6 +8,8 @@ import java.io.File
import Relations.Source
import Relations.SourceDependencies
import xsbti.api.{ Source => APISource }
+import xsbti.DependencyContext
+import xsbti.DependencyContext._
/**
* Provides mappings between source files, generated classes (products), and binaries.
diff --git a/compile/inc/src/test/scala/sbt/inc/AnalysisTest.scala b/compile/inc/src/test/scala/sbt/inc/AnalysisTest.scala
index 9df812685..1b0450e25 100644
--- a/compile/inc/src/test/scala/sbt/inc/AnalysisTest.scala
+++ b/compile/inc/src/test/scala/sbt/inc/AnalysisTest.scala
@@ -7,6 +7,7 @@ import sbt.inc.TestCaseGenerators._
import org.scalacheck._
import Gen._
import Prop._
+import xsbti.DependencyContext._
object AnalysisTest extends Properties("Analysis") {
// Merge and split a hard-coded trivial example.
diff --git a/compile/inc/src/test/scala/sbt/inc/TestCaseGenerators.scala b/compile/inc/src/test/scala/sbt/inc/TestCaseGenerators.scala
index d0628a7e4..2037dddda 100644
--- a/compile/inc/src/test/scala/sbt/inc/TestCaseGenerators.scala
+++ b/compile/inc/src/test/scala/sbt/inc/TestCaseGenerators.scala
@@ -10,6 +10,7 @@ import Gen._
import sbt.Relation
import xsbti.api._
import xsbti.SafeLazy
+import xsbti.DependencyContext._
/**
* Scalacheck generators for Analysis objects and their substructures.
diff --git a/compile/interface/src/main/scala/xsbt/Dependency.scala b/compile/interface/src/main/scala/xsbt/Dependency.scala
index 5fb688c73..d7f7b570f 100644
--- a/compile/interface/src/main/scala/xsbt/Dependency.scala
+++ b/compile/interface/src/main/scala/xsbt/Dependency.scala
@@ -6,6 +6,8 @@ package xsbt
import scala.tools.nsc.{ io, symtab, Phase }
import io.{ AbstractFile, PlainFile, ZipArchive }
import symtab.Flags
+import xsbti.DependencyContext
+import xsbti.DependencyContext._
import java.io.File
@@ -41,22 +43,22 @@ final class Dependency(val global: CallbackGlobal) extends LocateClassFile {
if (global.callback.nameHashing) {
val dependenciesByMemberRef = extractDependenciesByMemberRef(unit)
for (on <- dependenciesByMemberRef)
- processDependency(on, inherited = false)
+ processDependency(on, context = DependencyByMemberRef)
val dependenciesByInheritance = extractDependenciesByInheritance(unit)
for (on <- dependenciesByInheritance)
- processDependency(on, inherited = true)
+ processDependency(on, context = DependencyByInheritance)
} else {
- for (on <- unit.depends) processDependency(on, inherited = false)
- for (on <- inheritedDependencies.getOrElse(sourceFile, Nil: Iterable[Symbol])) processDependency(on, inherited = true)
+ for (on <- unit.depends) processDependency(on, context = DependencyByMemberRef)
+ for (on <- inheritedDependencies.getOrElse(sourceFile, Nil: Iterable[Symbol])) processDependency(on, context = DependencyByInheritance)
}
/**
* Handles dependency on given symbol by trying to figure out if represents a term
* that is coming from either source code (not necessarily compiled in this compilation
* run) or from class file and calls respective callback method.
*/
- def processDependency(on: Symbol, inherited: Boolean) {
- def binaryDependency(file: File, className: String) = callback.binaryDependency(file, className, sourceFile, inherited)
+ def processDependency(on: Symbol, context: DependencyContext) {
+ def binaryDependency(file: File, className: String) = callback.binaryDependency(file, className, sourceFile, context)
val onSource = on.sourceFile
if (onSource == null) {
classFile(on) match {
@@ -70,7 +72,7 @@ final class Dependency(val global: CallbackGlobal) extends LocateClassFile {
case None => ()
}
} else if (onSource.file != sourceFile)
- callback.sourceDependency(onSource.file, sourceFile, inherited)
+ callback.sourceDependency(onSource.file, sourceFile, context)
}
}
}
diff --git a/compile/interface/src/test/scala/xsbt/ScalaCompilerForUnitTesting.scala b/compile/interface/src/test/scala/xsbt/ScalaCompilerForUnitTesting.scala
index 926be962f..f3ebd73e9 100644
--- a/compile/interface/src/test/scala/xsbt/ScalaCompilerForUnitTesting.scala
+++ b/compile/interface/src/test/scala/xsbt/ScalaCompilerForUnitTesting.scala
@@ -12,6 +12,7 @@ import xsbti.api.Definition
import xsbti.api.Def
import xsbt.api.SameAPI
import sbt.ConsoleLogger
+import xsbti.DependencyContext._
import ScalaCompilerForUnitTesting.ExtractedSourceDependencies
@@ -68,11 +69,11 @@ class ScalaCompilerForUnitTesting(nameHashing: Boolean = false) {
val memberRefFileDeps = testCallback.sourceDependencies collect {
// false indicates that those dependencies are not introduced by inheritance
- case (target, src, false) => (src, target)
+ case (target, src, DependencyByMemberRef) => (src, target)
}
val inheritanceFileDeps = testCallback.sourceDependencies collect {
// true indicates that those dependencies are introduced by inheritance
- case (target, src, true) => (src, target)
+ case (target, src, DependencyByInheritance) => (src, target)
}
def toSymbols(src: File, target: File): (Symbol, Symbol) = (fileToSymbol(src), fileToSymbol(target))
val memberRefDeps = memberRefFileDeps map { case (src, target) => toSymbols(src, target) }
diff --git a/compile/persist/src/main/scala/sbt/inc/AnalysisFormats.scala b/compile/persist/src/main/scala/sbt/inc/AnalysisFormats.scala
index 1af8278aa..d74b81645 100644
--- a/compile/persist/src/main/scala/sbt/inc/AnalysisFormats.scala
+++ b/compile/persist/src/main/scala/sbt/inc/AnalysisFormats.scala
@@ -7,6 +7,7 @@ package inc
import xsbti.api.{ Source, Compilation }
import xsbti.{ Position, Problem, Severity }
import xsbti.compile.{ CompileOrder, Output => APIOutput, SingleOutput, MultipleOutput }
+import xsbti.DependencyContext._
import MultipleOutput.OutputGroup
import java.io.File
import sbinary._
diff --git a/interface/src/main/java/xsbti/AnalysisCallback.java b/interface/src/main/java/xsbti/AnalysisCallback.java
index 0e083d4eb..88b190e80 100644
--- a/interface/src/main/java/xsbti/AnalysisCallback.java
+++ b/interface/src/main/java/xsbti/AnalysisCallback.java
@@ -12,13 +12,29 @@ public interface AnalysisCallback
* passed to this method. Dependencies on classes generated by sources not in the current compilation will
* be passed as class dependencies to the classDependency method.
* If publicInherited is true, this dependency is a result of inheritance by a
- * template accessible outside of the source file. */
+ * template accessible outside of the source file.
+ * @deprecated Use `sourceDependency(File dependsOn, File source, DependencyContext context)` instead. */
+ @Deprecated
public void sourceDependency(File dependsOn, File source, boolean publicInherited);
+ /** 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
+ * be passed as class dependencies to the classDependency method.
+ * context gives information about the context in which this dependency has been extracted.
+ * See xsbti.DependencyContext for the list of existing dependency contexts. */
+ public void sourceDependency(File dependsOn, File source, DependencyContext context);
/** Called to indicate that the source file source depends on the top-level
* class named name from class or jar file binary.
* If publicInherited is true, this dependency is a result of inheritance by a
- * template accessible outside of the source file. */
+ * template accessible outside of the source file.
+ * @deprecated Use `binaryDependency(File binary, String name, File source, DependencyContext context)` instead. */
+ @Deprecated
public void binaryDependency(File binary, String name, File source, boolean publicInherited);
+ /** Called to indicate that the source file source depends on the top-level
+ * class named name from class or jar file binary.
+ * context gives information about the context in which this dependency has been extracted.
+ * See xsbti.DependencyContext for the list of existing dependency contexts. */
+ public void binaryDependency(File binary, String name, File source, DependencyContext context);
/** 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);
diff --git a/interface/src/main/java/xsbti/DependencyContext.java b/interface/src/main/java/xsbti/DependencyContext.java
new file mode 100644
index 000000000..15cfa76d1
--- /dev/null
+++ b/interface/src/main/java/xsbti/DependencyContext.java
@@ -0,0 +1,22 @@
+package xsbti;
+
+/**
+ * Enumeration of existing dependency contexts.
+ * Dependency contexts represent the various kind of dependencies that
+ * can exist between symbols.
+ */
+public enum DependencyContext {
+ /**
+ * Represents a direct dependency between two symbols :
+ * object Foo
+ * object Bar { def foo = Foo }
+ */
+ DependencyByMemberRef,
+
+ /**
+ * Represents an inheritance dependency between two symbols :
+ * class A
+ * class B extends A
+ */
+ DependencyByInheritance
+}
diff --git a/interface/src/test/scala/xsbti/TestCallback.scala b/interface/src/test/scala/xsbti/TestCallback.scala
index 3ea7e32e1..13b65df79 100644
--- a/interface/src/test/scala/xsbti/TestCallback.scala
+++ b/interface/src/test/scala/xsbti/TestCallback.scala
@@ -3,17 +3,26 @@ package xsbti
import java.io.File
import scala.collection.mutable.ArrayBuffer
import xsbti.api.SourceAPI
+import xsbti.DependencyContext._
class TestCallback(override val nameHashing: Boolean = false) extends AnalysisCallback
{
- val sourceDependencies = new ArrayBuffer[(File, File, Boolean)]
- val binaryDependencies = new ArrayBuffer[(File, String, File, Boolean)]
+ val sourceDependencies = new ArrayBuffer[(File, File, DependencyContext)]
+ val binaryDependencies = new ArrayBuffer[(File, String, File, DependencyContext)]
val products = new ArrayBuffer[(File, File, String)]
val usedNames = scala.collection.mutable.Map.empty[File, Set[String]].withDefaultValue(Set.empty)
val apis: scala.collection.mutable.Map[File, SourceAPI] = scala.collection.mutable.Map.empty
- 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 sourceDependency(dependsOn: File, source: File, inherited: Boolean) {
+ val context = if(inherited) DependencyByInheritance else DependencyByMemberRef
+ sourceDependency(dependsOn, source, context)
+ }
+ def sourceDependency(dependsOn: File, source: File, context: DependencyContext) { sourceDependencies += ((dependsOn, source, context)) }
+ def binaryDependency(binary: File, name: String, source: File, inherited: Boolean) {
+ val context = if(inherited) DependencyByInheritance else DependencyByMemberRef
+ binaryDependency(binary, name, source, context)
+ }
+ def binaryDependency(binary: File, name: String, source: File, context: DependencyContext) { binaryDependencies += ((binary, name, source, context)) }
def generatedClass(source: File, module: File, name: String) { products += ((source, module, name)) }
def usedName(source: File, name: String) { usedNames(source) += name }
diff --git a/util/classfile/src/main/scala/sbt/classfile/Analyze.scala b/util/classfile/src/main/scala/sbt/classfile/Analyze.scala
index 0b12916b3..9df04f1f1 100644
--- a/util/classfile/src/main/scala/sbt/classfile/Analyze.scala
+++ b/util/classfile/src/main/scala/sbt/classfile/Analyze.scala
@@ -12,6 +12,8 @@ import java.lang.annotation.Annotation
import java.lang.reflect.Method
import java.lang.reflect.Modifier.{ STATIC, PUBLIC, ABSTRACT }
import java.net.URL
+import xsbti.DependencyContext
+import xsbti.DependencyContext._
private[sbt] object Analyze {
def apply[T](newClasses: Seq[File], sources: Seq[File], log: Logger)(analysis: xsbti.AnalysisCallback, loader: ClassLoader, readAPI: (File, Seq[Class[_]]) => Set[String]) {
@@ -41,26 +43,26 @@ private[sbt] object Analyze {
for ((source, classFiles) <- sourceToClassFiles) {
val publicInherited = readAPI(source, classFiles.toSeq.flatMap(c => load(c.className, Some("Error reading API from class file"))))
- def processDependency(tpe: String, inherited: Boolean) {
+ def processDependency(tpe: String, context: DependencyContext) {
trapAndLog(log) {
for (url <- Option(loader.getResource(tpe.replace('.', '/') + ClassExt)); file <- urlAsFile(url, log)) {
if (url.getProtocol == "jar")
- analysis.binaryDependency(file, tpe, source, inherited)
+ analysis.binaryDependency(file, tpe, source, context)
else {
assume(url.getProtocol == "file")
productToSource.get(file) match {
- case Some(dependsOn) => analysis.sourceDependency(dependsOn, source, inherited)
- case None => analysis.binaryDependency(file, tpe, source, inherited)
+ case Some(dependsOn) => analysis.sourceDependency(dependsOn, source, context)
+ case None => analysis.binaryDependency(file, tpe, source, context)
}
}
}
}
}
- def processDependencies(tpes: Iterable[String], inherited: Boolean): Unit = tpes.foreach(tpe => processDependency(tpe, inherited))
+ def processDependencies(tpes: Iterable[String], context: DependencyContext): Unit = tpes.foreach(tpe => processDependency(tpe, context))
val notInherited = classFiles.flatMap(_.types).toSet -- publicInherited
- processDependencies(notInherited, false)
- processDependencies(publicInherited, true)
+ processDependencies(notInherited, DependencyByMemberRef)
+ processDependencies(publicInherited, DependencyByInheritance)
}
for (source <- sources filterNot sourceToClassFiles.keySet) {