diff --git a/compile/interface/src/main/scala/xsbt/API.scala b/compile/interface/src/main/scala/xsbt/API.scala index b20219823..451cc8aa8 100644 --- a/compile/interface/src/main/scala/xsbt/API.scala +++ b/compile/interface/src/main/scala/xsbt/API.scala @@ -39,6 +39,7 @@ final class API(val global: CallbackGlobal) extends Compat def processScalaUnit(unit: CompilationUnit) { val sourceFile = unit.source.file.file + currentSourceFile = sourceFile debug("Traversing " + sourceFile) val traverser = new TopLevelHandler(sourceFile) traverser.apply(unit.body) @@ -50,6 +51,10 @@ final class API(val global: CallbackGlobal) extends Compat } } + // Tracks the source file associated with the CompilationUnit currently being processed by the API phase. + // This is used when recording inheritance dependencies. + private[this] var currentSourceFile: File = _ + // this cache reduces duplicate work both here and when persisting // caches on other structures had minimal effect on time and cache size // (tried: Definition, Modifier, Path, Id, String) @@ -237,8 +242,18 @@ final class API(val global: CallbackGlobal) extends Compat mkStructure(s, baseTypes, ds, is) } - private def mkStructure(s: Symbol, bases: List[Type], declared: List[Symbol], inherited: List[Symbol]): xsbti.api.Structure = + // If true, this template is publicly visible and should be processed as a public inheritance dependency. + // Local classes and local refinements will never be traversed by the api phase, so we don't need to check for that. + private[this] def isPublicStructure(s: Symbol): Boolean = + s.isStructuralRefinement || + // do not consider templates that are private[this] or private + !(s.isPrivate && (s.privateWithin == NoSymbol || s.isLocal)) + + private def mkStructure(s: Symbol, bases: List[Type], declared: List[Symbol], inherited: List[Symbol]): xsbti.api.Structure = { + if(isPublicStructure(s)) + addInheritedDependencies(currentSourceFile, bases.map(_.dealias.typeSymbol)) new xsbti.api.Structure(lzy(types(s, bases)), lzy(processDefinitions(s, declared)), lzy(processDefinitions(s, inherited))) + } private def processDefinitions(in: Symbol, defs: List[Symbol]): Array[xsbti.api.Definition] = sort(defs.toArray).flatMap( (d: Symbol) => definition(in, d)) private[this] def sort(defs: Array[Symbol]): Array[Symbol] = { diff --git a/compile/interface/src/main/scala/xsbt/Analyzer.scala b/compile/interface/src/main/scala/xsbt/Analyzer.scala index 728224b96..0989f7a67 100644 --- a/compile/interface/src/main/scala/xsbt/Analyzer.scala +++ b/compile/interface/src/main/scala/xsbt/Analyzer.scala @@ -33,9 +33,11 @@ final class Analyzer(val global: CallbackGlobal) extends Compat // build dependencies structure val sourceFile = unit.source.file.file callback.beginSource(sourceFile) - for(on <- unit.depends) + 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) + def binaryDependency(file: File, className: String) = callback.binaryDependency(file, className, sourceFile /*, inherited*/) val onSource = on.sourceFile if(onSource == null) { @@ -53,7 +55,7 @@ final class Analyzer(val global: CallbackGlobal) extends Compat } } else - callback.sourceDependency(onSource.file, sourceFile) + callback.sourceDependency(onSource.file, sourceFile /*, inherited*/) } // build list of generated classes diff --git a/compile/interface/src/main/scala/xsbt/CompilerInterface.scala b/compile/interface/src/main/scala/xsbt/CompilerInterface.scala index abb1407cd..3a02bd138 100644 --- a/compile/interface/src/main/scala/xsbt/CompilerInterface.scala +++ b/compile/interface/src/main/scala/xsbt/CompilerInterface.scala @@ -42,6 +42,11 @@ sealed abstract class CallbackGlobal(settings: Settings, reporter: reporters.Rep case multi: MultipleOutput => multi.outputGroups.toStream map (_.outputDirectory) } } + // Map source files to public inherited dependencies. These dependencies are tracked as the symbol for the dealiased base class. + val inheritedDependencies = new mutable.HashMap[File, mutable.Set[Symbol]] + def addInheritedDependencies(file: File, deps: Iterable[Symbol]) { + inheritedDependencies.getOrElseUpdate(file, new mutable.HashSet) ++= deps + } } class InterfaceCompileFailed(val arguments: Array[String], val problems: Array[Problem], override val toString: String) extends xsbti.CompileFailed