mirror of
https://github.com/sbt/sbt.git
synced 2026-09-03 16:39:24 +02:00
Merge branch '0.13.10' into wip/0.13.10-merge
This commit is contained in:
@@ -261,7 +261,7 @@ object ClassToAPI {
|
||||
def modifiers(i: Int): api.Modifiers =
|
||||
{
|
||||
import Modifier.{ isAbstract, isFinal }
|
||||
new api.Modifiers(isAbstract(i), false, isFinal(i), false, false, false, false)
|
||||
new api.Modifiers(isAbstract(i), false, isFinal(i), false, false, false, false, false)
|
||||
}
|
||||
def access(i: Int, pkg: Option[String]): api.Access =
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@ object APIUtil {
|
||||
}
|
||||
val byteToModifiers = (b: Byte) => {
|
||||
def x(bit: Int) = (b & (1 << bit)) != 0
|
||||
new Modifiers(x(0), x(1), x(2), x(3), x(4), x(5), x(6))
|
||||
new Modifiers(x(0), x(1), x(2), x(3), x(4), x(5), x(6), x(7))
|
||||
}
|
||||
|
||||
def isScalaSourceName(name: String): Boolean = name.endsWith(".scala")
|
||||
|
||||
@@ -139,16 +139,37 @@ final class HashAPI(includePrivate: Boolean, includeParamNames: Boolean, include
|
||||
{
|
||||
hash = startHash(0)
|
||||
hashSymmetric(s.packages, hashPackage)
|
||||
hashDefinitions(s.definitions, true)
|
||||
hashDefinitions(s.definitions, topLevel = true, isTrait = false)
|
||||
finalizeHash
|
||||
}
|
||||
|
||||
def hashPackage(p: Package) = hashString(p.name)
|
||||
|
||||
@deprecated("Use the overload that indicates if the enclosing definition is a trait.", "0.14")
|
||||
def hashDefinitions(ds: Seq[Definition], topLevel: Boolean): Unit =
|
||||
hashDefinitions(ds, topLevel, isTrait = false)
|
||||
|
||||
def hashDefinitions(ds: Seq[Definition], topLevel: Boolean, isTrait: Boolean): Unit =
|
||||
{
|
||||
def isPublic(d: Definition): Boolean = d.access match { case _: xsbti.api.Public => true; case _ => false }
|
||||
def isTraitBreaker(d: Definition): Boolean = d match {
|
||||
// Vars and vals in traits introduce getters, setters and fields in the implementing classes.
|
||||
// See test `source-dependencies/trait-private-var
|
||||
case _: FieldLike => true
|
||||
// Objects in traits introduce fields in the implementing classes.
|
||||
// See test `source-dependencies/trait-private-object`
|
||||
case cl: ClassLike => cl.definitionType == DefinitionType.Module
|
||||
// super calls introduce accessors that are not part of the public API
|
||||
case d: Def => d.modifiers.isSuperAccessor
|
||||
case _ => false
|
||||
}
|
||||
val includedPrivateDefinitions =
|
||||
if (!includePrivate && !topLevel && isTrait) {
|
||||
ds filter (x => isTraitBreaker(x) && !isPublic(x))
|
||||
} else Seq.empty
|
||||
|
||||
val defs = SameAPI.filterDefinitions(ds, topLevel, includePrivate)
|
||||
hashSymmetric(defs, hashDefinition)
|
||||
hashSymmetric(includedPrivateDefinitions ++ defs, hashDefinition)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -356,9 +377,9 @@ final class HashAPI(includePrivate: Boolean, includeParamNames: Boolean, include
|
||||
def hashStructure0(structure: Structure, includeDefinitions: Boolean, isTrait: Boolean = false): Unit = {
|
||||
extend(StructureHash)
|
||||
hashTypes(structure.parents, includeDefinitions)
|
||||
if (includeDefinitions || isTrait) {
|
||||
hashDefinitions(structure.declared, isTrait)
|
||||
hashDefinitions(structure.inherited, isTrait)
|
||||
if (includeDefinitions) {
|
||||
hashDefinitions(structure.declared, topLevel = false, isTrait)
|
||||
hashDefinitions(structure.inherited, topLevel = false, isTrait)
|
||||
}
|
||||
}
|
||||
def hashParameters(parameters: Seq[TypeParameter], base: Type): Unit =
|
||||
|
||||
@@ -165,20 +165,39 @@ class NameHashingSpecification extends Specification {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that private members are included in the hash of the public API of traits.
|
||||
* Including the private members of traits is required because classes that implement a trait
|
||||
* have to define the private members of the trait. Therefore, if a private member of a trait is added,
|
||||
* modified or removed we need to recompile the classes that implement this trait.
|
||||
* Checks that private vars are included in the hash of the public API of traits.
|
||||
* Including the private vars of traits is required because classes that implement a trait
|
||||
* have to define getters and setters for these vars.
|
||||
* For instance, if trait Foo is initially defined as:
|
||||
* trait Foo { private val x = new A }
|
||||
* trait Foo { private var x = new A }
|
||||
* changing it to
|
||||
* trait Foo { private val x = new B }
|
||||
* trait Foo { private var x = new B }
|
||||
* requires us to recompile all implementors of trait Foo, because scalac generates setters and getters
|
||||
* for the private fields of trait Foo in its implementor. If the clients of trait Foo are not recompiled,
|
||||
* for the private vars of trait Foo in its implementor. If the clients of trait Foo are not recompiled,
|
||||
* we get abstract method errors at runtime, because the types expected by the setter (for instance) does not
|
||||
* match.
|
||||
*/
|
||||
"private members in traits" in {
|
||||
"private var in traits are included in API hash" in {
|
||||
/* trait Foo { private var x } */
|
||||
val fooTrait1 =
|
||||
simpleTrait("Foo",
|
||||
simpleStructure(new Var(emptyType, "x", privateAccess, defaultModifiers, Array.empty)),
|
||||
publicAccess)
|
||||
|
||||
/* trait Foo */
|
||||
val fooTrait2 =
|
||||
simpleTrait("Foo",
|
||||
simpleStructure(),
|
||||
publicAccess)
|
||||
|
||||
val api1 = new SourceAPI(Array.empty, Array(fooTrait1))
|
||||
val api2 = new SourceAPI(Array.empty, Array(fooTrait2))
|
||||
|
||||
HashAPI(api1) !== HashAPI(api2)
|
||||
|
||||
}
|
||||
|
||||
"private vals in traits are included in API hash" in {
|
||||
/* trait Foo { private val x } */
|
||||
val fooTrait1 =
|
||||
simpleTrait("Foo",
|
||||
@@ -198,15 +217,97 @@ class NameHashingSpecification extends Specification {
|
||||
|
||||
}
|
||||
|
||||
"private objects in traits are included in API hash" in {
|
||||
/* trait Foo { private object x } */
|
||||
val fooTrait1 =
|
||||
simpleTrait("Foo",
|
||||
simpleStructure(
|
||||
new ClassLike(DefinitionType.Module, lzy(emptyType), lzy(simpleStructure()), Array.empty, Array.empty, "x", privateAccess, defaultModifiers, Array.empty)),
|
||||
publicAccess)
|
||||
|
||||
/* trait Foo */
|
||||
val fooTrait2 =
|
||||
simpleTrait("Foo",
|
||||
simpleStructure(),
|
||||
publicAccess)
|
||||
|
||||
val api1 = new SourceAPI(Array.empty, Array(fooTrait1))
|
||||
val api2 = new SourceAPI(Array.empty, Array(fooTrait2))
|
||||
|
||||
HashAPI(api1) !== HashAPI(api2)
|
||||
|
||||
}
|
||||
|
||||
"private non-synthetic def in traits are not included in API hash" in {
|
||||
/* trait Foo { private def x } */
|
||||
val fooTrait1 =
|
||||
simpleTrait("Foo",
|
||||
simpleStructure(new Def(Array.empty, emptyType, Array.empty, "x", privateAccess, defaultModifiers, Array.empty)),
|
||||
publicAccess)
|
||||
|
||||
/* trait Foo */
|
||||
val fooTrait2 =
|
||||
simpleTrait("Foo",
|
||||
simpleStructure(),
|
||||
publicAccess)
|
||||
|
||||
val api1 = new SourceAPI(Array.empty, Array(fooTrait1))
|
||||
val api2 = new SourceAPI(Array.empty, Array(fooTrait2))
|
||||
|
||||
HashAPI(api1) === HashAPI(api2)
|
||||
|
||||
}
|
||||
|
||||
"private synthetic def in traits are included in API hash" in {
|
||||
/* trait Foo { private <superaccessor> def x } */
|
||||
val modifiers = new xsbti.api.Modifiers(false, false, false, false, false, false, false, true)
|
||||
val fooTrait1 =
|
||||
simpleTrait("Foo",
|
||||
simpleStructure(new Def(Array.empty, emptyType, Array.empty, "x", privateAccess, modifiers, Array.empty)),
|
||||
publicAccess)
|
||||
|
||||
/* trait Foo */
|
||||
val fooTrait2 =
|
||||
simpleTrait("Foo",
|
||||
simpleStructure(),
|
||||
publicAccess)
|
||||
|
||||
val api1 = new SourceAPI(Array.empty, Array(fooTrait1))
|
||||
val api2 = new SourceAPI(Array.empty, Array(fooTrait2))
|
||||
|
||||
HashAPI(api1) !== HashAPI(api2)
|
||||
|
||||
}
|
||||
|
||||
"private types in traits are included not in API hash" in {
|
||||
/* trait Foo { private type x } */
|
||||
val fooTrait1 =
|
||||
simpleTrait("Foo",
|
||||
simpleStructure(new TypeAlias(emptyType, Array.empty, "x", privateAccess, defaultModifiers, Array.empty)),
|
||||
publicAccess)
|
||||
|
||||
/* trait Foo */
|
||||
val fooTrait2 =
|
||||
simpleTrait("Foo",
|
||||
simpleStructure(),
|
||||
publicAccess)
|
||||
|
||||
val api1 = new SourceAPI(Array.empty, Array(fooTrait1))
|
||||
val api2 = new SourceAPI(Array.empty, Array(fooTrait2))
|
||||
|
||||
HashAPI(api1) === HashAPI(api2)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that private members in non-top-level traits are included as well.
|
||||
* Checks that private vars in non-top-level traits are included as well.
|
||||
*/
|
||||
"private members in nested traits" in {
|
||||
/* class A { trait Foo { private val x } } */
|
||||
"private variables in nested traits are include in the API hash" in {
|
||||
/* class A { trait Foo { private var x } } */
|
||||
val classA1 =
|
||||
simpleClass("A",
|
||||
simpleTrait("Foo",
|
||||
simpleStructure(new Val(emptyType, "x", privateAccess, defaultModifiers, Array.empty)),
|
||||
simpleStructure(new Var(emptyType, "x", privateAccess, defaultModifiers, Array.empty)),
|
||||
publicAccess))
|
||||
|
||||
/* class A { trait Foo } */
|
||||
@@ -226,12 +327,12 @@ class NameHashingSpecification extends Specification {
|
||||
/**
|
||||
* Checks that private traits are NOT included in the hash.
|
||||
*/
|
||||
"private traits" in {
|
||||
/* class Foo { private trait T { private val x } } */
|
||||
"private inner traits are not included in the API hash" in {
|
||||
/* class Foo { private trait T { private var x } } */
|
||||
val classFoo1 =
|
||||
simpleClass("Foo",
|
||||
simpleTrait("T",
|
||||
simpleStructure(new Val(emptyType, "x", privateAccess, defaultModifiers, Array.empty)),
|
||||
simpleStructure(new Var(emptyType, "x", privateAccess, defaultModifiers, Array.empty)),
|
||||
privateAccess))
|
||||
|
||||
/** class Foo { private trait T } */
|
||||
@@ -256,10 +357,10 @@ class NameHashingSpecification extends Specification {
|
||||
* Checks that private members are NOT included in the hash of the public API of classes.
|
||||
*/
|
||||
"private members in classes are not included in the api hash" in {
|
||||
/* class Foo { private val x } */
|
||||
/* class Foo { private var x } */
|
||||
val classFoo1 =
|
||||
simpleClass("Foo",
|
||||
simpleStructure(new Val(emptyType, "x", privateAccess, defaultModifiers, Array.empty)))
|
||||
simpleStructure(new Var(emptyType, "x", privateAccess, defaultModifiers, Array.empty)))
|
||||
|
||||
/* class Foo */
|
||||
val classFoo2 =
|
||||
@@ -274,9 +375,9 @@ class NameHashingSpecification extends Specification {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that private members do NOT contribute to name hashes.
|
||||
* Test for https://github.com/sbt/sbt/issues/2324
|
||||
*/
|
||||
* Checks that private members do NOT contribute to name hashes.
|
||||
* Test for https://github.com/sbt/sbt/issues/2324
|
||||
*/
|
||||
"private members in classes do not contribute to name hashes" in {
|
||||
/* class Foo { private val x } */
|
||||
val classFoo =
|
||||
@@ -336,6 +437,6 @@ class NameHashingSpecification extends Specification {
|
||||
private val strTpe = new Projection(emptyType, "String")
|
||||
private val publicAccess = new Public
|
||||
private val privateAccess = new Private(new Unqualified)
|
||||
private val defaultModifiers = new Modifiers(false, false, false, false, false, false, false)
|
||||
private val defaultModifiers = new Modifiers(false, false, false, false, false, false, false, false)
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user