diff --git a/internal/compiler-interface/src/main/java/xsbti/compile/DefaultExternalHooks.java b/internal/compiler-interface/src/main/java/xsbti/compile/DefaultExternalHooks.java index ef644c719f..f4bc253482 100644 --- a/internal/compiler-interface/src/main/java/xsbti/compile/DefaultExternalHooks.java +++ b/internal/compiler-interface/src/main/java/xsbti/compile/DefaultExternalHooks.java @@ -11,18 +11,25 @@ package xsbti.compile; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; import java.util.Optional; public class DefaultExternalHooks implements ExternalHooks { private Optional lookup = Optional.empty(); private Optional classFileManager = Optional.empty(); + private GetProvenance getProvenance = NoProvenance.INSTANCE; - public DefaultExternalHooks(Optional lookup, Optional classFileManager) { + public DefaultExternalHooks( + Optional lookup, + Optional classFileManager, + GetProvenance getProvenance + ) { this.lookup = lookup; this.classFileManager = classFileManager; + this.getProvenance = getProvenance; + } + + public DefaultExternalHooks(Optional lookup, Optional classFileManager) { + this(lookup, classFileManager, NoProvenance.INSTANCE); } @Override @@ -35,22 +42,25 @@ public Optional getExternalClassFileManager() { return classFileManager; } + @Override public GetProvenance getProvenance() { return getProvenance; } + @Override public ExternalHooks withExternalClassFileManager(ClassFileManager externalClassFileManager) { Optional external = Optional.of(externalClassFileManager); Optional mixedManager = classFileManager.isPresent() ? Optional.of(WrappedClassFileManager.of(classFileManager.get(), external)) : external; - return new DefaultExternalHooks(lookup, mixedManager); + return new DefaultExternalHooks(lookup, mixedManager, getProvenance); } @Override public ExternalHooks withExternalLookup(ExternalHooks.Lookup externalLookup) { - return new DefaultExternalHooks(Optional.of(externalLookup), classFileManager); + Optional externalLookup1 = Optional.of(externalLookup); + return new DefaultExternalHooks(externalLookup1, classFileManager, getProvenance); } @Override - public Map extraHooks() { - return Collections.unmodifiableMap(new HashMap<>()); + public ExternalHooks withGetProvenance(GetProvenance getProvenance) { + return new DefaultExternalHooks(lookup, classFileManager, getProvenance); } } diff --git a/internal/compiler-interface/src/main/java/xsbti/compile/ExternalHooks.java b/internal/compiler-interface/src/main/java/xsbti/compile/ExternalHooks.java index 676b0a99a6..d628ceba72 100644 --- a/internal/compiler-interface/src/main/java/xsbti/compile/ExternalHooks.java +++ b/internal/compiler-interface/src/main/java/xsbti/compile/ExternalHooks.java @@ -11,7 +11,7 @@ package xsbti.compile; -import java.util.Map; +import java.nio.file.Path; import java.util.Optional; import java.util.Set; import xsbti.VirtualFileRef; @@ -61,6 +61,15 @@ interface Lookup { Optional hashClasspath(VirtualFile[] classpath); } + interface GetProvenance { + String get(Path path); + } + + enum NoProvenance implements GetProvenance { + INSTANCE; + @Override public String get(Path path) { return ""; } + } + /** * Returns the implementation of a lookup mechanism to be used instead of * the internal lookup provided by the default implementation. @@ -76,6 +85,8 @@ interface Lookup { */ Optional getExternalClassFileManager(); + default GetProvenance getProvenance() { return NoProvenance.INSTANCE; } + /** * Returns an instance of hooks that executes the external passed class file manager. * @@ -95,8 +106,5 @@ interface Lookup { */ ExternalHooks withExternalLookup(Lookup externalLookup); - /** - * Until interface stabilizes, park experimental hooks here. - */ - Map extraHooks(); + default ExternalHooks withGetProvenance(GetProvenance getProvenance) { return this; } } diff --git a/internal/zinc-core/src/main/scala/sbt/internal/inc/Hooks.scala b/internal/zinc-core/src/main/scala/sbt/internal/inc/Hooks.scala deleted file mode 100644 index c2fddb4df4..0000000000 --- a/internal/zinc-core/src/main/scala/sbt/internal/inc/Hooks.scala +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Zinc - The incremental compiler for Scala. - * Copyright Lightbend, Inc. and Mark Harrah - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package sbt -package internal -package inc - -import java.nio.file.Path -import java.util.{ Map => jMap } -import java.util.Optional - -import sbt.util.InterfaceUtil -import xsbti.api.AnalyzedClass -import xsbti.compile.ExternalHooks - -object Hooks { - private val QUICK_API = "QUICKAPI" - private val GET_PROVENANCE = "GETPROVENANCE" - - /** - * None => Found class somewhere outside of project. No analysis possible. - * Some(analyzed) if analyzed.provenance.isEmpty => Couldn't find it. - * Some(analyzed) => good - */ - private[sbt] def quickAPI(hooks: ExternalHooks): String => Option[AnalyzedClass] = { - val f = getOrElse(hooks, QUICK_API, (_: String) => Optional.empty[AnalyzedClass]) - c => InterfaceUtil.toOption(f(c)) - } - - def addQuickAPI(m: jMap[String, Object], f: String => Optional[AnalyzedClass]): Unit = { - m.put(QUICK_API, f) - () - } - - private[sbt] def getProvenance(hooks: ExternalHooks): Path => String = { - getOrElse(hooks, GET_PROVENANCE, (_: Path) => "") - } - - def addGetProvenance(m: jMap[String, Object], f: Path => String): Unit = { - m.put(GET_PROVENANCE, f) - () - } - - private def getOrElse[A <: AnyRef](hooks: ExternalHooks, key: String, alt: A): A = - hooks.extraHooks().getOrDefault(key, alt).asInstanceOf[A] -} diff --git a/internal/zinc-core/src/main/scala/sbt/internal/inc/Incremental.scala b/internal/zinc-core/src/main/scala/sbt/internal/inc/Incremental.scala index 430d114b9d..556c4331ba 100644 --- a/internal/zinc-core/src/main/scala/sbt/internal/inc/Incremental.scala +++ b/internal/zinc-core/src/main/scala/sbt/internal/inc/Incremental.scala @@ -25,7 +25,6 @@ import xsbti.api._ import xsbti.compile.{ CompileAnalysis, DependencyChanges, - ExternalHooks, IncOptions, Output, ClassFileManager => XClassFileManager @@ -81,13 +80,12 @@ object Incremental { ): (Boolean, Analysis) = { log.debug(s"[zinc] IncrementalCompile -----------") val previous = previous0 match { case a: Analysis => a } - val externalHooks = options.externalHooks() val currentStamper = Stamps.initial(stamper) val internalBinaryToSourceClassName = (binaryClassName: String) => previous.relations.productClassName.reverse(binaryClassName).headOption val internalSourceToClassNamesMap: VirtualFile => Set[String] = (f: VirtualFile) => previous.relations.classNames(f) - val externalAPI = getExternalAPI(externalHooks, lookup) + val externalAPI = getExternalAPI(lookup) try { incrementalCompile( sources, @@ -167,9 +165,8 @@ object Incremental { val previous = previous0 match { case a: Analysis => a } val runProfiler = profiler.profileRun val incremental: IncrementalCommon = new IncrementalNameHashing(log, options, runProfiler) - val hooks = options.externalHooks val initialChanges = - incremental.detectInitialChanges(sources, previous, current, lookup, converter, hooks, output) + incremental.detectInitialChanges(sources, previous, current, lookup, converter, output) log.debug(s"> initialChanges = $initialChanges") val binaryChanges = new DependencyChanges { val modifiedLibraries = initialChanges.libraryDeps.toArray @@ -318,9 +315,7 @@ private final class AnalysisCallback( private[this] val compilation: Compilation = Compilation(compileStartTime, output) private val hooks = options.externalHooks - - private val provenance = - jo2o(output.getSingleOutput).fold("")(Hooks.getProvenance(hooks)(_)).intern + private val provenance = jo2o(output.getSingleOutput).fold("")(hooks.getProvenance.get(_)).intern override def toString = (List("Class APIs", "Object APIs", "Library deps", "Products", "Source deps") zip diff --git a/internal/zinc-core/src/main/scala/sbt/internal/inc/IncrementalCommon.scala b/internal/zinc-core/src/main/scala/sbt/internal/inc/IncrementalCommon.scala index fcaa7a4e87..e11a69a7c1 100644 --- a/internal/zinc-core/src/main/scala/sbt/internal/inc/IncrementalCommon.scala +++ b/internal/zinc-core/src/main/scala/sbt/internal/inc/IncrementalCommon.scala @@ -19,9 +19,7 @@ import xsbt.api.APIUtil import xsbti.api.AnalyzedClass import xsbti.compile.{ Changes, - CompileAnalysis, DependencyChanges, - ExternalHooks, IncOptions, Output, ClassFileManager => XClassFileManager @@ -325,14 +323,12 @@ private[inc] abstract class IncrementalCommon( stamps: ReadStamps, lookup: Lookup, converter: FileConverter, - hooks: ExternalHooks, output: Output )(implicit equivS: Equiv[XStamp]): InitialChanges = { import IncrementalCommon.isLibraryModified import lookup.lookupAnalyzedClass val previous = previousAnalysis.stamps val previousRelations = previousAnalysis.relations - val quickAPI: String => Option[AnalyzedClass] = Hooks.quickAPI(hooks) val sourceChanges: Changes[VirtualFileRef] = lookup.changedSources(previousAnalysis).getOrElse { val previousSources: Set[VirtualFileRef] = previous.allSources.toSet @@ -379,12 +375,7 @@ private[inc] abstract class IncrementalCommon( val externalApiChanges: APIChanges = { val incrementalExternalChanges = { val previousAPIs = previousAnalysis.apis - val externalFinder = (binaryClassName: String) => - (quickAPI(binaryClassName) match { - case Some(api) if api.provenance.isEmpty => - lookupAnalyzedClass(binaryClassName) // found without a provenance, so looking it up - case x => x // fast-track success: either found w/ provenance or not found at all - }).getOrElse(APIs.emptyAnalyzedClass) + val externalFinder = lookupAnalyzedClass(_: String).getOrElse(APIs.emptyAnalyzedClass) detectAPIChanges(previousAPIs.allExternals, previousAPIs.externalAPI, externalFinder) } diff --git a/internal/zinc-core/src/main/scala/sbt/internal/inc/Lookup.scala b/internal/zinc-core/src/main/scala/sbt/internal/inc/Lookup.scala index 5488161552..97b49438a8 100644 --- a/internal/zinc-core/src/main/scala/sbt/internal/inc/Lookup.scala +++ b/internal/zinc-core/src/main/scala/sbt/internal/inc/Lookup.scala @@ -49,6 +49,7 @@ trait Lookup extends ExternalLookup { def lookupAnalysis(binaryClassName: String): Option[CompileAnalysis] def lookupAnalyzedClass(binaryClassName: String): Option[AnalyzedClass] = { + // This is the default, slow, route, via Analysis; overridden in LookupImpl for the fast-track. for { analysis0 <- lookupAnalysis(binaryClassName) analysis = analysis0 match { case a: Analysis => a } @@ -71,6 +72,9 @@ trait ExternalLookup extends ExternalHooks.Lookup { * Find the external `AnalyzedClass` (from another analysis) given a class name. * * @return The `AnalyzedClass` associated with the given class name, if one is found. + * Optional.empty() => Found class somewhere outside of project. No analysis possible. + * Optional.of(analyzed) if analyzed.provenance.isEmpty => Couldn't find it. + * Optional.of(analyzed) => good */ def lookupAnalyzedClass(binaryClassName: String): Option[AnalyzedClass] diff --git a/zinc/src/main/scala/sbt/internal/inc/LookupImpl.scala b/zinc/src/main/scala/sbt/internal/inc/LookupImpl.scala index 651fd1305c..9a100bdccb 100644 --- a/zinc/src/main/scala/sbt/internal/inc/LookupImpl.scala +++ b/zinc/src/main/scala/sbt/internal/inc/LookupImpl.scala @@ -58,8 +58,13 @@ class LookupImpl(compileConfiguration: CompileConfiguration, previousSetup: Opti override def lookupAnalyzedClass(binaryClassName: String): Option[AnalyzedClass] = { externalLookup match { // not flatMap so that external lookup can fast-track returning None - case Some(externalLookup) => externalLookup.lookupAnalyzedClass(binaryClassName) - case _ => super.lookupAnalyzedClass(binaryClassName) + case Some(externalLookup) => + externalLookup.lookupAnalyzedClass(binaryClassName) match { + case Some(api) if api.provenance.isEmpty => // found but w/o provenance, so go slow route + super.lookupAnalyzedClass(binaryClassName) + case x => x // fast-track success: either found w/ provenance or not found at all + } + case _ => super.lookupAnalyzedClass(binaryClassName) } }