From a1885e42e263702113b7b4fb3890b8210480cd1e Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Fri, 3 Jan 2020 22:04:12 +0000 Subject: [PATCH] Report the loss of trait init methods In the encoding of traits the presence of a method with a body (a "concrete method") triggers the generation of a trait initialisation method, "$init$", which will be invoked by subclasses during construction. The effect this has is that dropping the last concrete method(s) from a trait _removes_ the trait init method, which is a binary incompatible change to client's subclasses. Fixes #426 --- .../com/typesafe/tools/mima/core/ClassInfo.scala | 11 ++++++----- .../com/typesafe/tools/mima/core/MemberInfo.scala | 6 +++++- .../problems.txt | 0 .../v1/A.scala | 0 .../v2/A.scala | 0 .../problems.txt | 1 + .../problems-2.11.txt | 0 .../problems.txt | 1 + .../v1/A.scala | 0 .../v2/A.scala | 2 +- .../problems.txt | 0 .../problems-2.11.txt | 0 .../problems.txt | 1 + .../v1/A.scala | 0 .../v2/A.scala | 2 +- .../problems.txt | 0 16 files changed, 16 insertions(+), 8 deletions(-) rename functional-tests/src/test/{class-narrowing-method-type-in-new-version-ok => class-narrowing-method-type-in-new-version-nok}/problems.txt (100%) rename functional-tests/src/test/{class-narrowing-method-type-in-new-version-ok => class-narrowing-method-type-in-new-version-nok}/v1/A.scala (100%) rename functional-tests/src/test/{class-narrowing-method-type-in-new-version-ok => class-narrowing-method-type-in-new-version-nok}/v2/A.scala (100%) rename functional-tests/src/test/{trait-deleting-concrete-methods-is-ok => trait-deleting-concrete-methods-is-nok}/problems-2.11.txt (100%) create mode 100644 functional-tests/src/test/trait-deleting-concrete-methods-is-nok/problems.txt rename functional-tests/src/test/{trait-deleting-concrete-methods-is-ok => trait-deleting-concrete-methods-is-nok}/v1/A.scala (100%) rename functional-tests/src/test/{trait-deleting-concrete-methods-is-ok => trait-deleting-concrete-methods-is-nok}/v2/A.scala (74%) delete mode 100644 functional-tests/src/test/trait-deleting-concrete-methods-is-ok/problems.txt rename functional-tests/src/test/{trait-pushing-up-concrete-methods-is-ok => trait-pushing-up-concrete-methods-is-nok}/problems-2.11.txt (100%) create mode 100644 functional-tests/src/test/trait-pushing-up-concrete-methods-is-nok/problems.txt rename functional-tests/src/test/{trait-pushing-up-concrete-methods-is-ok => trait-pushing-up-concrete-methods-is-nok}/v1/A.scala (100%) rename functional-tests/src/test/{trait-pushing-up-concrete-methods-is-ok => trait-pushing-up-concrete-methods-is-nok}/v2/A.scala (65%) delete mode 100644 functional-tests/src/test/trait-pushing-up-concrete-methods-is-ok/problems.txt diff --git a/core/src/main/scala/com/typesafe/tools/mima/core/ClassInfo.scala b/core/src/main/scala/com/typesafe/tools/mima/core/ClassInfo.scala index b50d3cee..58922ffc 100644 --- a/core/src/main/scala/com/typesafe/tools/mima/core/ClassInfo.scala +++ b/core/src/main/scala/com/typesafe/tools/mima/core/ClassInfo.scala @@ -99,14 +99,15 @@ sealed abstract class ClassInfo(val owner: PackageInfo) extends InfoLike with Eq thisAndSuperClasses.flatMap(_.fields.get(field.bytecodeName)) final def lookupClassMethods(method: MethodInfo): Iterator[MethodInfo] = { - method.bytecodeName match { - case MemberInfo.ConstructorName => methods.get(MemberInfo.ConstructorName) // constructors are not inherited - case name => thisAndSuperClasses.flatMap(_.methods.get(name)) - } + val name = method.bytecodeName + if (name == MemberInfo.ConstructorName) methods.get(name) // constructors are not inherited + else if (method.isStatic) methods.get(name) // static methods are not inherited + else thisAndSuperClasses.flatMap(_.methods.get(name)) } private def lookupInterfaceMethods(method: MethodInfo): Iterator[MethodInfo] = - allInterfaces.iterator.flatMap(_.methods.get(method.bytecodeName)) + if (method.isStatic) Iterator.empty // static methods are not inherited + else allInterfaces.iterator.flatMap(_.methods.get(method.bytecodeName)) final def lookupMethods(method: MethodInfo): Iterator[MethodInfo] = lookupClassMethods(method) ++ lookupInterfaceMethods(method) diff --git a/core/src/main/scala/com/typesafe/tools/mima/core/MemberInfo.scala b/core/src/main/scala/com/typesafe/tools/mima/core/MemberInfo.scala index d678b2bb..ffb836ec 100644 --- a/core/src/main/scala/com/typesafe/tools/mima/core/MemberInfo.scala +++ b/core/src/main/scala/com/typesafe/tools/mima/core/MemberInfo.scala @@ -54,13 +54,17 @@ private[mima] final class MethodInfo(owner: ClassInfo, bytecodeName: String, fla def matchesType(other: MethodInfo): Boolean = parametersDesc == other.parametersDesc private def isDefaultGetter: Boolean = decodedName.contains("$default$") + private def isTraitInit: Boolean = decodedName == "$init$" private def isExtensionMethod: Boolean = { var i = decodedName.length - 1 while (i >= 0 && Character.isDigit(decodedName.charAt(i))) i -= 1 decodedName.substring(0, i + 1).endsWith("$extension") } - def nonAccessible: Boolean = !isPublic || isSynthetic || (hasSyntheticName && !isExtensionMethod && !isDefaultGetter) + def nonAccessible: Boolean = { + !isPublic || isSynthetic || + (hasSyntheticName && !(isExtensionMethod || isDefaultGetter || isTraitInit)) + } override def toString = s"def $bytecodeName: $descriptor" } diff --git a/functional-tests/src/test/class-narrowing-method-type-in-new-version-ok/problems.txt b/functional-tests/src/test/class-narrowing-method-type-in-new-version-nok/problems.txt similarity index 100% rename from functional-tests/src/test/class-narrowing-method-type-in-new-version-ok/problems.txt rename to functional-tests/src/test/class-narrowing-method-type-in-new-version-nok/problems.txt diff --git a/functional-tests/src/test/class-narrowing-method-type-in-new-version-ok/v1/A.scala b/functional-tests/src/test/class-narrowing-method-type-in-new-version-nok/v1/A.scala similarity index 100% rename from functional-tests/src/test/class-narrowing-method-type-in-new-version-ok/v1/A.scala rename to functional-tests/src/test/class-narrowing-method-type-in-new-version-nok/v1/A.scala diff --git a/functional-tests/src/test/class-narrowing-method-type-in-new-version-ok/v2/A.scala b/functional-tests/src/test/class-narrowing-method-type-in-new-version-nok/v2/A.scala similarity index 100% rename from functional-tests/src/test/class-narrowing-method-type-in-new-version-ok/v2/A.scala rename to functional-tests/src/test/class-narrowing-method-type-in-new-version-nok/v2/A.scala diff --git a/functional-tests/src/test/moving-method-upward-from-trait-to-class-nok/problems.txt b/functional-tests/src/test/moving-method-upward-from-trait-to-class-nok/problems.txt index eb680da0..2764108a 100644 --- a/functional-tests/src/test/moving-method-upward-from-trait-to-class-nok/problems.txt +++ b/functional-tests/src/test/moving-method-upward-from-trait-to-class-nok/problems.txt @@ -1 +1,2 @@ method foo()Int in interface B does not have a correspondent in new version +synthetic static method $init$(B)Unit in interface B does not have a correspondent in new version diff --git a/functional-tests/src/test/trait-deleting-concrete-methods-is-ok/problems-2.11.txt b/functional-tests/src/test/trait-deleting-concrete-methods-is-nok/problems-2.11.txt similarity index 100% rename from functional-tests/src/test/trait-deleting-concrete-methods-is-ok/problems-2.11.txt rename to functional-tests/src/test/trait-deleting-concrete-methods-is-nok/problems-2.11.txt diff --git a/functional-tests/src/test/trait-deleting-concrete-methods-is-nok/problems.txt b/functional-tests/src/test/trait-deleting-concrete-methods-is-nok/problems.txt new file mode 100644 index 00000000..a875dade --- /dev/null +++ b/functional-tests/src/test/trait-deleting-concrete-methods-is-nok/problems.txt @@ -0,0 +1 @@ +synthetic static method $init$(B)Unit in interface B does not have a correspondent in new version diff --git a/functional-tests/src/test/trait-deleting-concrete-methods-is-ok/v1/A.scala b/functional-tests/src/test/trait-deleting-concrete-methods-is-nok/v1/A.scala similarity index 100% rename from functional-tests/src/test/trait-deleting-concrete-methods-is-ok/v1/A.scala rename to functional-tests/src/test/trait-deleting-concrete-methods-is-nok/v1/A.scala diff --git a/functional-tests/src/test/trait-deleting-concrete-methods-is-ok/v2/A.scala b/functional-tests/src/test/trait-deleting-concrete-methods-is-nok/v2/A.scala similarity index 74% rename from functional-tests/src/test/trait-deleting-concrete-methods-is-ok/v2/A.scala rename to functional-tests/src/test/trait-deleting-concrete-methods-is-nok/v2/A.scala index 70a33c91..86d0c22c 100644 --- a/functional-tests/src/test/trait-deleting-concrete-methods-is-ok/v2/A.scala +++ b/functional-tests/src/test/trait-deleting-concrete-methods-is-nok/v2/A.scala @@ -6,4 +6,4 @@ trait A { trait B extends A -class C extends B \ No newline at end of file +class C extends B diff --git a/functional-tests/src/test/trait-deleting-concrete-methods-is-ok/problems.txt b/functional-tests/src/test/trait-deleting-concrete-methods-is-ok/problems.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/functional-tests/src/test/trait-pushing-up-concrete-methods-is-ok/problems-2.11.txt b/functional-tests/src/test/trait-pushing-up-concrete-methods-is-nok/problems-2.11.txt similarity index 100% rename from functional-tests/src/test/trait-pushing-up-concrete-methods-is-ok/problems-2.11.txt rename to functional-tests/src/test/trait-pushing-up-concrete-methods-is-nok/problems-2.11.txt diff --git a/functional-tests/src/test/trait-pushing-up-concrete-methods-is-nok/problems.txt b/functional-tests/src/test/trait-pushing-up-concrete-methods-is-nok/problems.txt new file mode 100644 index 00000000..22ed1402 --- /dev/null +++ b/functional-tests/src/test/trait-pushing-up-concrete-methods-is-nok/problems.txt @@ -0,0 +1 @@ +synthetic static method $init$(B)Unit in interface B does not have a correspondent in new version \ No newline at end of file diff --git a/functional-tests/src/test/trait-pushing-up-concrete-methods-is-ok/v1/A.scala b/functional-tests/src/test/trait-pushing-up-concrete-methods-is-nok/v1/A.scala similarity index 100% rename from functional-tests/src/test/trait-pushing-up-concrete-methods-is-ok/v1/A.scala rename to functional-tests/src/test/trait-pushing-up-concrete-methods-is-nok/v1/A.scala diff --git a/functional-tests/src/test/trait-pushing-up-concrete-methods-is-ok/v2/A.scala b/functional-tests/src/test/trait-pushing-up-concrete-methods-is-nok/v2/A.scala similarity index 65% rename from functional-tests/src/test/trait-pushing-up-concrete-methods-is-ok/v2/A.scala rename to functional-tests/src/test/trait-pushing-up-concrete-methods-is-nok/v2/A.scala index 0380fa56..a8ae8dca 100644 --- a/functional-tests/src/test/trait-pushing-up-concrete-methods-is-ok/v2/A.scala +++ b/functional-tests/src/test/trait-pushing-up-concrete-methods-is-nok/v2/A.scala @@ -4,4 +4,4 @@ trait A { -trait B extends A \ No newline at end of file +trait B extends A diff --git a/functional-tests/src/test/trait-pushing-up-concrete-methods-is-ok/problems.txt b/functional-tests/src/test/trait-pushing-up-concrete-methods-is-ok/problems.txt deleted file mode 100644 index e69de29b..00000000