mirror of https://github.com/sbt/sbt.git
Merge pull request #2540 from eed3si9n/wip/synthetic
Adds withIncludeSynthToNameHashing.
This commit is contained in:
commit
ba72faab35
|
|
@ -232,23 +232,23 @@ object FileFunction {
|
|||
type UpdateFunction = (ChangeReport[File], ChangeReport[File]) => Set[File]
|
||||
|
||||
/**
|
||||
Generic change-detection helper used to help build / artifact generation /
|
||||
etc. steps detect whether or not they need to run. Returns a function whose
|
||||
input is a Set of input files, and subsequently executes the action function
|
||||
(which does the actual work: compiles, generates resources, etc.), returning
|
||||
a Set of output files that it generated.
|
||||
|
||||
The input file and resulting output file state is cached in
|
||||
cacheBaseDirectory. On each invocation, the state of the input and output
|
||||
files from the previous run is compared against the cache, as is the set of
|
||||
input files. If a change in file state / input files set is detected, the
|
||||
action function is re-executed.
|
||||
|
||||
@param cacheBaseDirectory The folder in which to store
|
||||
@param inStyle The strategy by which to detect state change in the input files from the previous run
|
||||
@param outStyle The strategy by which to detect state change in the output files from the previous run
|
||||
@param action The work function, which receives a list of input files and returns a list of output files
|
||||
*/
|
||||
* Generic change-detection helper used to help build / artifact generation /
|
||||
* etc. steps detect whether or not they need to run. Returns a function whose
|
||||
* input is a Set of input files, and subsequently executes the action function
|
||||
* (which does the actual work: compiles, generates resources, etc.), returning
|
||||
* a Set of output files that it generated.
|
||||
*
|
||||
* The input file and resulting output file state is cached in
|
||||
* cacheBaseDirectory. On each invocation, the state of the input and output
|
||||
* files from the previous run is compared against the cache, as is the set of
|
||||
* input files. If a change in file state / input files set is detected, the
|
||||
* action function is re-executed.
|
||||
*
|
||||
* @param cacheBaseDirectory The folder in which to store
|
||||
* @param inStyle The strategy by which to detect state change in the input files from the previous run
|
||||
* @param outStyle The strategy by which to detect state change in the output files from the previous run
|
||||
* @param action The work function, which receives a list of input files and returns a list of output files
|
||||
*/
|
||||
def cached(cacheBaseDirectory: File, inStyle: FilesInfo.Style = FilesInfo.lastModified, outStyle: FilesInfo.Style = FilesInfo.exists)(action: Set[File] => Set[File]): Set[File] => Set[File] =
|
||||
cached(cacheBaseDirectory)(inStyle, outStyle)((in, out) => action(in.checked))
|
||||
|
||||
|
|
|
|||
|
|
@ -206,6 +206,7 @@ private final class AnalysisCallback(internalMap: File => Option[File], external
|
|||
def usedName(sourceFile: File, name: String) = add(usedNames, sourceFile, name)
|
||||
|
||||
def nameHashing: Boolean = options.nameHashing
|
||||
def includeSynthToNameHashing: Boolean = options.includeSynthToNameHashing
|
||||
|
||||
def get: Analysis = addUsedNames(addCompilation(addProductsAndDeps(Analysis.empty(nameHashing = nameHashing))))
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,11 @@ final class IncOptions(
|
|||
* Once Scala compiler sources are refactored to work well with name hashing algorithm this option will be
|
||||
* deleted immediately.
|
||||
*/
|
||||
val antStyle: Boolean) extends Product with Serializable {
|
||||
val antStyle: Boolean,
|
||||
/**
|
||||
* Include synthetic methods into the dependency tracking by name hashing.
|
||||
*/
|
||||
val includeSynthToNameHashing: Boolean) extends Product with Serializable {
|
||||
|
||||
/**
|
||||
* Secondary constructor introduced to make IncOptions to be binary compatible with version that didn't have
|
||||
|
|
@ -90,59 +94,72 @@ final class IncOptions(
|
|||
apiDiffContextSize: Int, apiDumpDirectory: Option[java.io.File], newClassfileManager: () => ClassfileManager) = {
|
||||
this(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager, IncOptions.recompileOnMacroDefDefault, IncOptions.nameHashingDefault,
|
||||
IncOptions.antStyleDefault)
|
||||
IncOptions.antStyleDefault, IncOptions.includeSynthToNameHashingDefault)
|
||||
}
|
||||
|
||||
def this(transitiveStep: Int, recompileAllFraction: Double, relationsDebug: Boolean, apiDebug: Boolean,
|
||||
apiDiffContextSize: Int, apiDumpDirectory: Option[java.io.File], newClassfileManager: () => ClassfileManager,
|
||||
recompileOnMacroDef: Boolean, nameHashing: Boolean, antStyle: Boolean) = {
|
||||
this(transitiveStep, recompileAllFraction, relationsDebug, apiDebug,
|
||||
apiDiffContextSize, apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing,
|
||||
antStyle, IncOptions.includeSynthToNameHashingDefault)
|
||||
}
|
||||
|
||||
assert(!(antStyle && nameHashing), "Name hashing and Ant-style cannot be enabled at the same time.")
|
||||
|
||||
def withTransitiveStep(transitiveStep: Int): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle)
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing)
|
||||
}
|
||||
|
||||
def withRecompileAllFraction(recompileAllFraction: Double): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle)
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing)
|
||||
}
|
||||
|
||||
def withRelationsDebug(relationsDebug: Boolean): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle)
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing)
|
||||
}
|
||||
|
||||
def withApiDebug(apiDebug: Boolean): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle)
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing)
|
||||
}
|
||||
|
||||
def withApiDiffContextSize(apiDiffContextSize: Int): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle)
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing)
|
||||
}
|
||||
|
||||
def withApiDumpDirectory(apiDumpDirectory: Option[File]): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle)
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing)
|
||||
}
|
||||
|
||||
def withNewClassfileManager(newClassfileManager: () => ClassfileManager): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle)
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing)
|
||||
}
|
||||
|
||||
def withRecompileOnMacroDef(recompileOnMacroDef: Boolean): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle)
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing)
|
||||
}
|
||||
|
||||
def withNameHashing(nameHashing: Boolean): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle)
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing)
|
||||
}
|
||||
|
||||
def withIncludeSynthToNameHashing(includeSynthToNameHashing: Boolean): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing)
|
||||
}
|
||||
|
||||
def withAntStyle(antStyle: Boolean): IncOptions = {
|
||||
new IncOptions(transitiveStep, recompileAllFraction, relationsDebug, apiDebug, apiDiffContextSize,
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle)
|
||||
apiDumpDirectory, newClassfileManager, recompileOnMacroDef, nameHashing, antStyle, includeSynthToNameHashing)
|
||||
}
|
||||
|
||||
//- EXPANDED CASE CLASS METHOD BEGIN -//
|
||||
|
|
@ -219,6 +236,8 @@ object IncOptions extends Serializable {
|
|||
private val recompileOnMacroDefDefault: Boolean = true
|
||||
private[sbt] val nameHashingDefault: Boolean = true
|
||||
private val antStyleDefault: Boolean = false
|
||||
// This should default to false
|
||||
private[sbt] val includeSynthToNameHashingDefault = java.lang.Boolean.getBoolean("sbt.inc.include_synth")
|
||||
val Default = IncOptions(
|
||||
// 1. recompile changed sources
|
||||
// 2(3). recompile direct dependencies and transitive public inheritance dependencies of sources with API changes in 1(2).
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ import scala.tools.nsc._
|
|||
class ExtractUsedNames[GlobalType <: CallbackGlobal](val global: GlobalType) extends Compat {
|
||||
import global._
|
||||
|
||||
@inline def debug(msg: => String) = if (settings.verbose.value) inform(msg)
|
||||
|
||||
def extract(unit: CompilationUnit): Set[String] = {
|
||||
val tree = unit.body
|
||||
val extractedByTreeWalk = extractByTreeWalk(tree)
|
||||
|
|
@ -122,7 +124,7 @@ class ExtractUsedNames[GlobalType <: CallbackGlobal](val global: GlobalType) ext
|
|||
}
|
||||
|
||||
(symbol != NoSymbol) &&
|
||||
!symbol.isSynthetic &&
|
||||
(callback.includeSynthToNameHashing || !symbol.isSynthetic) &&
|
||||
!emptyName(symbol.name)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class ExtractAPISpecification extends Specification {
|
|||
|
||||
def stableExistentialNames: Boolean = {
|
||||
def compileAndGetFooMethodApi(src: String): Def = {
|
||||
val compilerForTesting = new ScalaCompilerForUnitTesting
|
||||
val compilerForTesting = new ScalaCompilerForUnitTesting(nameHashing = false)
|
||||
val sourceApi = compilerForTesting.extractApiFromSrc(src)
|
||||
val FooApi = sourceApi.definitions().find(_.name() == "Foo").get.asInstanceOf[ClassLike]
|
||||
val fooMethodApi = FooApi.structure().declared().find(_.name == "foo").get
|
||||
|
|
@ -66,7 +66,7 @@ class ExtractAPISpecification extends Specification {
|
|||
| class Foo extends Namers
|
||||
|}
|
||||
|""".stripMargin
|
||||
val compilerForTesting = new ScalaCompilerForUnitTesting
|
||||
val compilerForTesting = new ScalaCompilerForUnitTesting(nameHashing = false)
|
||||
val apis = compilerForTesting.extractApisFromSrcs(reuseCompilerInstance = false)(List(src1, src2), List(src2))
|
||||
val _ :: src2Api1 :: src2Api2 :: Nil = apis.toList
|
||||
val namerApi1 = selectNamer(src2Api1)
|
||||
|
|
@ -92,7 +92,7 @@ class ExtractAPISpecification extends Specification {
|
|||
val srcC6 = "class C6 extends AnyRef with X { self: X with Y => }"
|
||||
val srcC7 = "class C7 { _ => }"
|
||||
val srcC8 = "class C8 { self => }"
|
||||
val compilerForTesting = new ScalaCompilerForUnitTesting
|
||||
val compilerForTesting = new ScalaCompilerForUnitTesting(nameHashing = false)
|
||||
val apis = compilerForTesting.extractApisFromSrcs(reuseCompilerInstance = true)(
|
||||
List(srcX, srcY, srcC1, srcC2, srcC3, srcC4, srcC5, srcC6, srcC7, srcC8)
|
||||
).map(x => collectFirstClass(x.definitions))
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import ScalaCompilerForUnitTesting.ExtractedSourceDependencies
|
|||
* Provides common functionality needed for unit tests that require compiling
|
||||
* source code using Scala compiler.
|
||||
*/
|
||||
class ScalaCompilerForUnitTesting(nameHashing: Boolean = false) {
|
||||
class ScalaCompilerForUnitTesting(nameHashing: Boolean, includeSynthToNameHashing: Boolean = false) {
|
||||
|
||||
/**
|
||||
* Compiles given source code using Scala compiler and returns API representation
|
||||
|
|
@ -127,7 +127,7 @@ class ScalaCompilerForUnitTesting(nameHashing: Boolean = false) {
|
|||
private def compileSrcs(groupedSrcs: List[List[String]],
|
||||
reuseCompilerInstance: Boolean): (Seq[File], TestCallback) = {
|
||||
withTemporaryDirectory { temp =>
|
||||
val analysisCallback = new TestCallback(nameHashing)
|
||||
val analysisCallback = new TestCallback(nameHashing, includeSynthToNameHashing)
|
||||
val classesDir = new File(temp, "classes")
|
||||
classesDir.mkdir()
|
||||
|
||||
|
|
|
|||
|
|
@ -59,4 +59,8 @@ public interface AnalysisCallback
|
|||
* Do not depend on it, please.
|
||||
*/
|
||||
boolean nameHashing();
|
||||
/**
|
||||
* Include synthetic methods into the dependency tracking by name hashing.
|
||||
*/
|
||||
boolean includeSynthToNameHashing();
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ import scala.collection.mutable.ArrayBuffer
|
|||
import xsbti.api.SourceAPI
|
||||
import xsbti.DependencyContext._
|
||||
|
||||
class TestCallback(override val nameHashing: Boolean = false) extends AnalysisCallback
|
||||
class TestCallback(override val nameHashing: Boolean, override val includeSynthToNameHashing: Boolean) extends AnalysisCallback
|
||||
{
|
||||
val sourceDependencies = new ArrayBuffer[(File, File, DependencyContext)]
|
||||
val binaryDependencies = new ArrayBuffer[(File, String, File, DependencyContext)]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
[@eed3si9n]: https://github.com/eed3si9n
|
||||
[@jsuereth]: https://github.com/jsuereth
|
||||
[@dwijnand]: http://github.com/dwijnand
|
||||
[@Duhemm]: http://github.com/Duhemm
|
||||
[@gkossakowski]: https://github.com/gkossakowski
|
||||
[2573]: https://github.com/sbt/sbt/issues/2537
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Provides a workaround flag `incOptions := incOptions.value.withIncludeSynthToNameHashing(true)` for name hashing not including synthetic methods. This will not be enabled by default in sbt 0.13. It can also enabled by passing `sbt.inc.include_synth=true` to JVM. [#2537][2573] by [@eed3si9h][@eed3si9h]
|
||||
|
|
@ -0,0 +1 @@
|
|||
case class A(a: Int)
|
||||
|
|
@ -0,0 +1 @@
|
|||
class B { def test(a: A) = a.copy() }
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
lazy val root = (project in file(".")).
|
||||
settings(
|
||||
scalaVersion := "2.11.7",
|
||||
incOptions := incOptions.value.withIncludeSynthToNameHashing(true)
|
||||
)
|
||||
|
|
@ -0,0 +1 @@
|
|||
case class A(a: Int) { private def copy = ??? }
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
> compile
|
||||
|
||||
$ copy-file changes/A.scala A.scala
|
||||
|
||||
-> compile
|
||||
Loading…
Reference in New Issue