Permalink
Browse files

Merge pull request #119 from dotta/issue/118-concrete-method-in-trait

Report a problem when adding a new trait/class w/ abstract members. Fix #118
  • Loading branch information...
2 parents dea5e6f + 54d54a8 commit 9a2fe123b18ff52b1dfa6ebc94fc8eea65589b22 Mirco Dotta committed on GitHub Sep 16, 2016
Showing with 246 additions and 13 deletions.
  1. +9 −2 core/src/main/scala/com/typesafe/tools/mima/core/ClassInfo.scala
  2. +4 −0 core/src/main/scala/com/typesafe/tools/mima/core/Problems.scala
  3. +1 −0 reporter/functional-tests/src/test/abstract-class-added-abstract-method-nok/problems.txt
  4. 0 ...nding-new-trait-with-no-concrete-method-ok → abstract-class-added-abstract-method-nok}/v1/A.scala
  5. +3 −0 reporter/functional-tests/src/test/abstract-class-added-abstract-method-nok/v2/A.scala
  6. +1 −0 ...-tests/src/test/abstract-class-extending-new-abstract-class-with-abstract-method-nok/problems.txt
  7. +15 −0 ...al-tests/src/test/abstract-class-extending-new-abstract-class-with-abstract-method-nok/v1/A.scala
  8. +26 −0 ...al-tests/src/test/abstract-class-extending-new-abstract-class-with-abstract-method-nok/v2/A.scala
  9. +1 −0 ...unctional-tests/src/test/abstract-class-extending-new-trait-with-abstract-method-nok/problems.txt
  10. +3 −0 .../functional-tests/src/test/abstract-class-extending-new-trait-with-abstract-method-nok/v1/A.scala
  11. +7 −0 .../functional-tests/src/test/abstract-class-extending-new-trait-with-abstract-method-nok/v2/A.scala
  12. 0 ...-no-concrete-method-ok → abstract-class-extending-new-trait-with-abstract-method-ok}/problems.txt
  13. +3 −0 ...r/functional-tests/src/test/abstract-class-extending-new-trait-with-abstract-method-ok/v1/A.scala
  14. +7 −0 ...r/functional-tests/src/test/abstract-class-extending-new-trait-with-abstract-method-ok/v2/A.scala
  15. 0 ...-no-concrete-method-ok → abstract-class-extending-new-trait-with-concrete-method-ok}/problems.txt
  16. +3 −0 ...r/functional-tests/src/test/abstract-class-extending-new-trait-with-concrete-method-ok/v1/A.scala
  17. +7 −0 ...r/functional-tests/src/test/abstract-class-extending-new-trait-with-concrete-method-ok/v2/A.scala
  18. +2 −0 ...l-tests/src/test/abstract-class-inherits-new-abstract-class-with-abstract-method-nok/problems.txt
  19. +7 −0 ...nal-tests/src/test/abstract-class-inherits-new-abstract-class-with-abstract-method-nok/v1/A.scala
  20. +10 −0 ...nal-tests/src/test/abstract-class-inherits-new-abstract-class-with-abstract-method-nok/v2/A.scala
  21. +2 −0 ...functional-tests/src/test/abstract-class-inherits-new-trait-with-abstract-method-nok/problems.txt
  22. +2 −0 ...r/functional-tests/src/test/abstract-class-inherits-new-trait-with-abstract-method-nok/v1/A.scala
  23. +6 −0 ...r/functional-tests/src/test/abstract-class-inherits-new-trait-with-abstract-method-nok/v2/A.scala
  24. +3 −0 ...unctional-tests/src/test/abstract-class-inherits-new-trait-with-abstract-method2-nok/problems.txt
  25. +4 −0 .../functional-tests/src/test/abstract-class-inherits-new-trait-with-abstract-method2-nok/v1/A.scala
  26. +6 −0 .../functional-tests/src/test/abstract-class-inherits-new-trait-with-abstract-method2-nok/v2/A.scala
  27. 0 reporter/functional-tests/src/test/added-abstract-class-in-new-version-ok/problems.txt
  28. +1 −0 reporter/functional-tests/src/test/added-abstract-class-in-new-version-ok/v1/A.scala
  29. +4 −0 reporter/functional-tests/src/test/added-abstract-class-in-new-version-ok/v2/A.scala
  30. 0 reporter/functional-tests/src/test/added-new-trait-with-abstract-methods-ok/problems.txt
  31. 0 reporter/functional-tests/src/test/added-new-trait-with-abstract-methods-ok/v1/A.scala
  32. +4 −0 reporter/functional-tests/src/test/added-new-trait-with-abstract-methods-ok/v2/A.scala
  33. 0 reporter/functional-tests/src/test/added-new-trait-with-concrete-methods-ok/problems.txt
  34. 0 reporter/functional-tests/src/test/added-new-trait-with-concrete-methods-ok/v1/A.scala
  35. +4 −0 reporter/functional-tests/src/test/added-new-trait-with-concrete-methods-ok/v2/A.scala
  36. 0 reporter/functional-tests/src/test/added-trait-in-new-version-ok/problems.txt
  37. +1 −0 reporter/functional-tests/src/test/added-trait-in-new-version-ok/v1/A.scala
  38. +5 −0 reporter/functional-tests/src/test/added-trait-in-new-version-ok/v2/A.scala
  39. +2 −0 reporter/functional-tests/src/test/class-added-abstract-method-in-new-version-nok/problems.txt
  40. +1 −0 reporter/functional-tests/src/test/class-added-abstract-method-in-new-version-nok/v1/A.scala
  41. +3 −0 reporter/functional-tests/src/test/class-added-abstract-method-in-new-version-nok/v2/A.scala
  42. +0 −5 reporter/functional-tests/src/test/class-extending-new-trait-with-no-concrete-method-ok/v2/A.scala
  43. 0 .../functional-tests/src/test/class-inherits-new-trait-with-shadowed-abstract-method-ok/problems.txt
  44. +6 −0 ...er/functional-tests/src/test/class-inherits-new-trait-with-shadowed-abstract-method-ok/v1/A.scala
  45. +7 −0 ...er/functional-tests/src/test/class-inherits-new-trait-with-shadowed-abstract-method-ok/v2/A.scala
  46. +1 −0 reporter/functional-tests/src/test/trait-added-abstract-method-nok/problems.txt
  47. 0 ...rait-extending-new-trait-with-no-concrete-method-ok → trait-added-abstract-method-nok}/v1/A.scala
  48. +3 −0 reporter/functional-tests/src/test/trait-added-abstract-method-nok/v2/A.scala
  49. +2 −0 reporter/functional-tests/src/test/trait-extending-new-trait-with-abstract-method-nok/problems.txt
  50. +1 −0 reporter/functional-tests/src/test/trait-extending-new-trait-with-abstract-method-nok/v1/A.scala
  51. 0 ...trait-with-no-concrete-method-ok → trait-extending-new-trait-with-abstract-method-nok}/v2/A.scala
  52. +1 −0 reporter/functional-tests/src/test/trait-extending-new-trait-with-concrete-method-nok/problems.txt
  53. +3 −0 ...er/functional-tests/src/test/trait-extending-new-trait-with-concrete-method-nok/v1/Foldable.scala
  54. +8 −0 ...er/functional-tests/src/test/trait-extending-new-trait-with-concrete-method-nok/v2/Foldable.scala
  55. +6 −0 reporter/functional-tests/src/test/trait-inherits-new-trait-with-abstract-method-nok/problems.txt
  56. +2 −0 reporter/functional-tests/src/test/trait-inherits-new-trait-with-abstract-method-nok/v1/A.scala
  57. +6 −0 reporter/functional-tests/src/test/trait-inherits-new-trait-with-abstract-method-nok/v2/A.scala
  58. +2 −0 reporter/functional-tests/src/test/trait-inherits-new-trait-with-concrete-method-nok/problems.txt
  59. +2 −0 reporter/functional-tests/src/test/trait-inherits-new-trait-with-concrete-method-nok/v1/A.scala
  60. +5 −0 reporter/functional-tests/src/test/trait-inherits-new-trait-with-concrete-method-nok/v2/A.scala
  61. +0 −1 reporter/src/main/scala/com/typesafe/tools/mima/lib/MiMaLib.scala
  62. +31 −2 reporter/src/main/scala/com/typesafe/tools/mima/lib/analyze/Analyzer.scala
  63. +3 −3 reporter/src/main/scala/com/typesafe/tools/mima/lib/analyze/Checker.scala
View
11 core/src/main/scala/com/typesafe/tools/mima/core/ClassInfo.scala
@@ -166,15 +166,22 @@ abstract class ClassInfo(val owner: PackageInfo) extends HasDeclarationName with
methods.iterator.toList.filterNot(concreteSet)
}
+ /** All deferred methods of this type as seen in the bytecode. */
+ def deferredMethodsInBytecode: List[MemberInfo] =
+ if(isTrait) methods.iterator.toList
+ else deferredMethods
+
/** The inherited traits in the linearization of this class or trait,
* except any traits inherited by its superclass.
* Traits appear in linearization order of this class or trait.
*/
lazy val directTraits: List[ClassInfo] = {
- /** All traits in the transitive, reflexive inheritance closure of given trait `t' */
+ /* All traits in the transitive, reflexive inheritance closure of given trait `t' */
def traitClosure(t: ClassInfo): List[ClassInfo] =
if (superClass.allTraits contains t) Nil
- else if (t.isTrait) parentsClosure(t) :+ t
+ // traits with only abstract methods are presented as interfaces, but nonetheless
+ // they should still be collected
+ else if (t.isInterface) parentsClosure(t) :+ t
else parentsClosure(t)
def parentsClosure(c: ClassInfo) =
View
4 core/src/main/scala/com/typesafe/tools/mima/core/Problems.scala
@@ -106,6 +106,10 @@ case class IncompatibleResultTypeProblem(oldmeth: MemberInfo, newmeth: MemberInf
// into two, in case the affected version is the other one, rather than the current one. (reversed if forward check).
abstract class AbstractMethodProblem(newmeth: MemberInfo) extends MemberProblem(newmeth)
+case class InheritedNewAbstractMethodProblem(clazz: ClassInfo, inheritedMethod: MemberInfo) extends AbstractMethodProblem(inheritedMethod) {
+ def description = affectedVersion => "abstract " + inheritedMethod.methodString+ " is inherited by class " + clazz.bytecodeName + " in " + affectedVersion + " version."
+}
+
case class DirectAbstractMethodProblem(newmeth: MemberInfo) extends AbstractMethodProblem(newmeth) {
def description = affectedVersion => "abstract " + newmeth.methodString + " does not have a correspondent in " + affectedVersion + " version"
}
View
1 reporter/functional-tests/src/test/abstract-class-added-abstract-method-nok/problems.txt
@@ -0,0 +1 @@
+abstract method foo()Unit in class A is present only in new version
View
0 ...ait-with-no-concrete-method-ok/v1/A.scala → ...lass-added-abstract-method-nok/v1/A.scala
File renamed without changes.
View
3 reporter/functional-tests/src/test/abstract-class-added-abstract-method-nok/v2/A.scala
@@ -0,0 +1,3 @@
+abstract class A {
+ def foo: Unit
+}
View
1 ...rc/test/abstract-class-extending-new-abstract-class-with-abstract-method-nok/problems.txt
@@ -0,0 +1 @@
+abstract method foo()Unit in class B is inherited by class A in new version.
View
15 .../src/test/abstract-class-extending-new-abstract-class-with-abstract-method-nok/v1/A.scala
@@ -0,0 +1,15 @@
+abstract class A {
+ def foo(a: A): Unit = ()
+}
+
+class C
+
+class D extends C
+
+abstract class E {
+ def bar(): E
+}
+
+class F extends E {
+ def bar(): E = new F
+}
View
26 .../src/test/abstract-class-extending-new-abstract-class-with-abstract-method-nok/v2/A.scala
@@ -0,0 +1,26 @@
+abstract class A extends B {
+ def foo(a: A): Unit = a.foo()
+}
+
+abstract class B {
+ def foo(): Unit
+}
+
+class C extends B {
+ def foo(): Unit = ()
+}
+
+class D extends C
+
+
+abstract class AA {
+ def bar(): AA
+}
+
+abstract class E extends AA {
+ def bar(): this.type
+}
+
+class F extends E {
+ def bar(): this.type = this
+}
View
1 ...l-tests/src/test/abstract-class-extending-new-trait-with-abstract-method-nok/problems.txt
@@ -0,0 +1 @@
+abstract method foo()Unit in interface B is inherited by class A in new version.
View
3 ...nal-tests/src/test/abstract-class-extending-new-trait-with-abstract-method-nok/v1/A.scala
@@ -0,0 +1,3 @@
+abstract class A {
+ def foo(a: A): Unit = ()
+}
View
7 ...nal-tests/src/test/abstract-class-extending-new-trait-with-abstract-method-nok/v2/A.scala
@@ -0,0 +1,7 @@
+abstract class A extends B {
+ def foo(a: A): Unit = a.foo()
+}
+
+trait B {
+ def foo(): Unit
+}
View
0 ...t-with-no-concrete-method-ok/problems.txt → ...rait-with-abstract-method-ok/problems.txt
File renamed without changes.
View
3 ...onal-tests/src/test/abstract-class-extending-new-trait-with-abstract-method-ok/v1/A.scala
@@ -0,0 +1,3 @@
+abstract class A {
+ def foo: Unit
+}
View
7 ...onal-tests/src/test/abstract-class-extending-new-trait-with-abstract-method-ok/v2/A.scala
@@ -0,0 +1,7 @@
+abstract class A extends B {
+ def foo: Unit
+}
+
+trait B {
+ def foo(): Unit
+}
View
0 ...t-with-no-concrete-method-ok/problems.txt → ...rait-with-concrete-method-ok/problems.txt
File renamed without changes.
View
3 ...onal-tests/src/test/abstract-class-extending-new-trait-with-concrete-method-ok/v1/A.scala
@@ -0,0 +1,3 @@
+abstract class A {
+ def foo(a: A): Unit = ()
+}
View
7 ...onal-tests/src/test/abstract-class-extending-new-trait-with-concrete-method-ok/v2/A.scala
@@ -0,0 +1,7 @@
+abstract class A extends B {
+ def foo(a: A): Unit = a.foo()
+}
+
+trait B {
+ def foo(): Unit = println("foo")
+}
View
2 ...src/test/abstract-class-inherits-new-abstract-class-with-abstract-method-nok/problems.txt
@@ -0,0 +1,2 @@
+abstract method foo()Unit in class AA is inherited by class A in new version.
+abstract method foo()Unit in class AA is inherited by class B in new version.
View
7 ...s/src/test/abstract-class-inherits-new-abstract-class-with-abstract-method-nok/v1/A.scala
@@ -0,0 +1,7 @@
+abstract class A
+abstract class B extends A
+abstract class C extends B {
+ def foo(): Unit
+}
+abstract class D extends C
+
View
10 ...s/src/test/abstract-class-inherits-new-abstract-class-with-abstract-method-nok/v2/A.scala
@@ -0,0 +1,10 @@
+abstract class AA {
+ def foo(): Unit
+}
+
+abstract class A extends AA
+abstract class B extends A
+abstract class C extends B {
+ def foo(): Unit
+}
+abstract class D extends C
View
2 ...al-tests/src/test/abstract-class-inherits-new-trait-with-abstract-method-nok/problems.txt
@@ -0,0 +1,2 @@
+abstract method foo()Unit in interface AA is inherited by class B in new version.
+abstract method foo()Unit in interface AA is inherited by class A in new version.
View
2 ...onal-tests/src/test/abstract-class-inherits-new-trait-with-abstract-method-nok/v1/A.scala
@@ -0,0 +1,2 @@
+trait A
+abstract class B
View
6 ...onal-tests/src/test/abstract-class-inherits-new-trait-with-abstract-method-nok/v2/A.scala
@@ -0,0 +1,6 @@
+trait AA {
+ def foo(): Unit
+}
+
+trait A extends AA
+abstract class B extends A
View
3 ...l-tests/src/test/abstract-class-inherits-new-trait-with-abstract-method2-nok/problems.txt
@@ -0,0 +1,3 @@
+abstract method foo()Int in interface AA is inherited by class A in new version.
+abstract method foo()Int in interface AA is inherited by class C in new version.
+abstract method foo()Int in interface AA is inherited by class B in new version.
View
4 ...nal-tests/src/test/abstract-class-inherits-new-trait-with-abstract-method2-nok/v1/A.scala
@@ -0,0 +1,4 @@
+trait A
+trait B
+abstract class C extends A with B
+
View
6 ...nal-tests/src/test/abstract-class-inherits-new-trait-with-abstract-method2-nok/v2/A.scala
@@ -0,0 +1,6 @@
+trait AA {
+ def foo: Int
+}
+trait A extends AA
+trait B extends A
+abstract class C extends B
View
0 reporter/functional-tests/src/test/added-abstract-class-in-new-version-ok/problems.txt
No changes.
View
1 reporter/functional-tests/src/test/added-abstract-class-in-new-version-ok/v1/A.scala
@@ -0,0 +1 @@
+class A
View
4 reporter/functional-tests/src/test/added-abstract-class-in-new-version-ok/v2/A.scala
@@ -0,0 +1,4 @@
+class A
+abstract class B {
+ def foo: Unit
+}
View
0 reporter/functional-tests/src/test/added-new-trait-with-abstract-methods-ok/problems.txt
No changes.
View
0 reporter/functional-tests/src/test/added-new-trait-with-abstract-methods-ok/v1/A.scala
No changes.
View
4 reporter/functional-tests/src/test/added-new-trait-with-abstract-methods-ok/v2/A.scala
@@ -0,0 +1,4 @@
+trait A {
+ val a: Int
+ def foo: Int
+}
View
0 reporter/functional-tests/src/test/added-new-trait-with-concrete-methods-ok/problems.txt
No changes.
View
0 reporter/functional-tests/src/test/added-new-trait-with-concrete-methods-ok/v1/A.scala
No changes.
View
4 reporter/functional-tests/src/test/added-new-trait-with-concrete-methods-ok/v2/A.scala
@@ -0,0 +1,4 @@
+trait A {
+ val a: Int = 2
+ def foo: Int = 3
+}
View
0 reporter/functional-tests/src/test/added-trait-in-new-version-ok/problems.txt
No changes.
View
1 reporter/functional-tests/src/test/added-trait-in-new-version-ok/v1/A.scala
@@ -0,0 +1 @@
+class A
View
5 reporter/functional-tests/src/test/added-trait-in-new-version-ok/v2/A.scala
@@ -0,0 +1,5 @@
+class A
+trait B {
+ def foo: Unit
+ def bar: Unit = ()
+}
View
2 ...ter/functional-tests/src/test/class-added-abstract-method-in-new-version-nok/problems.txt
@@ -0,0 +1,2 @@
+class A was concrete; is declared abstract in new version
+abstract method foo()Unit in class A is present only in new version
View
1 reporter/functional-tests/src/test/class-added-abstract-method-in-new-version-nok/v1/A.scala
@@ -0,0 +1 @@
+class A
View
3 reporter/functional-tests/src/test/class-added-abstract-method-in-new-version-nok/v2/A.scala
@@ -0,0 +1,3 @@
+abstract class A {
+ def foo: Unit
+}
View
5 ...functional-tests/src/test/class-extending-new-trait-with-no-concrete-method-ok/v2/A.scala
@@ -1,5 +0,0 @@
-abstract class A extends B
-trait B {
- val a: Int
- def foo: Int
-}
View
0 ...nal-tests/src/test/class-inherits-new-trait-with-shadowed-abstract-method-ok/problems.txt
No changes.
View
6 ...ional-tests/src/test/class-inherits-new-trait-with-shadowed-abstract-method-ok/v1/A.scala
@@ -0,0 +1,6 @@
+abstract class A {
+ def foo: Int
+}
+class B extends A {
+ override def foo: Int = 2
+}
View
7 ...ional-tests/src/test/class-inherits-new-trait-with-shadowed-abstract-method-ok/v2/A.scala
@@ -0,0 +1,7 @@
+trait AA {
+ def foo: Int
+}
+abstract class A extends AA
+class B extends A {
+ override def foo: Int = 2
+}
View
1 reporter/functional-tests/src/test/trait-added-abstract-method-nok/problems.txt
@@ -0,0 +1 @@
+abstract method foo()Unit in interface A is present only in new version
View
0 ...ait-with-no-concrete-method-ok/v1/A.scala → ...rait-added-abstract-method-nok/v1/A.scala
File renamed without changes.
View
3 reporter/functional-tests/src/test/trait-added-abstract-method-nok/v2/A.scala
@@ -0,0 +1,3 @@
+trait A {
+ def foo: Unit
+}
View
2 ...functional-tests/src/test/trait-extending-new-trait-with-abstract-method-nok/problems.txt
@@ -0,0 +1,2 @@
+abstract method a()Int in interface B is inherited by class A in new version.
+abstract method foo()Int in interface B is inherited by class A in new version.
View
1 ...r/functional-tests/src/test/trait-extending-new-trait-with-abstract-method-nok/v1/A.scala
@@ -0,0 +1 @@
+trait A
View
0 ...ait-with-no-concrete-method-ok/v2/A.scala → ...trait-with-abstract-method-nok/v2/A.scala
File renamed without changes.
View
1 ...functional-tests/src/test/trait-extending-new-trait-with-concrete-method-nok/problems.txt
@@ -0,0 +1 @@
+abstract method toList(java.lang.Object)scala.collection.immutable.List in trait FoldableToList is inherited by class Foldable in new version.
View
3 ...ional-tests/src/test/trait-extending-new-trait-with-concrete-method-nok/v1/Foldable.scala
@@ -0,0 +1,3 @@
+trait Foldable[F[_]]{
+ def foldLeft[A, B](fa: F[A], z: B)(f: (B, A) => B): B
+}
View
8 ...ional-tests/src/test/trait-extending-new-trait-with-concrete-method-nok/v2/Foldable.scala
@@ -0,0 +1,8 @@
+trait FoldableToList[F[_]] { self: Foldable[F] =>
+ def toList[A](fa: F[A]): List[A] =
+ self.foldLeft(fa, List.empty[A])((xs, x) => x :: xs).reverse
+}
+
+trait Foldable[F[_]] extends FoldableToList[F]{
+ def foldLeft[A, B](fa: F[A], z: B)(f: (B, A) => B): B
+}
View
6 .../functional-tests/src/test/trait-inherits-new-trait-with-abstract-method-nok/problems.txt
@@ -0,0 +1,6 @@
+abstract method foo()Int in trait AA is inherited by class A in new version.
+abstract synthetic method AA$_setter_|_=(Int)Unit in trait AA is inherited by class A in new version.
+abstract method bar()Int in trait AA is inherited by class A in new version.
+abstract method foo()Int in trait AA is inherited by class B in new version.
+abstract synthetic method AA$_setter_|_=(Int)Unit in trait AA is inherited by class B in new version.
+abstract method bar()Int in trait AA is inherited by class B in new version.
View
2 ...er/functional-tests/src/test/trait-inherits-new-trait-with-abstract-method-nok/v1/A.scala
@@ -0,0 +1,2 @@
+trait A
+trait B extends A
View
6 ...er/functional-tests/src/test/trait-inherits-new-trait-with-abstract-method-nok/v2/A.scala
@@ -0,0 +1,6 @@
+trait AA {
+ def foo: Int
+ val bar = 2
+}
+trait A extends AA
+trait B extends A
View
2 .../functional-tests/src/test/trait-inherits-new-trait-with-concrete-method-nok/problems.txt
@@ -0,0 +1,2 @@
+abstract method foo()Int in trait AA is inherited by class A in new version.
+abstract method foo()Int in trait AA is inherited by class B in new version.
View
2 ...er/functional-tests/src/test/trait-inherits-new-trait-with-concrete-method-nok/v1/A.scala
@@ -0,0 +1,2 @@
+trait A
+trait B extends A
View
5 ...er/functional-tests/src/test/trait-inherits-new-trait-with-concrete-method-nok/v2/A.scala
@@ -0,0 +1,5 @@
+trait AA {
+ def foo: Int = 2
+}
+trait A extends AA
+trait B extends A
View
1 reporter/src/main/scala/com/typesafe/tools/mima/lib/MiMaLib.scala
@@ -43,7 +43,6 @@ class MiMaLib(classpath: JavaClassPath, val log: Logging = ConsoleLogging) {
private def comparePackages(oldpkg: PackageInfo, newpkg: PackageInfo) {
- val traits = newpkg.traits // determine traits of new package first
for (oldclazz <- oldpkg.accessibleClasses) {
log.info("Analyzing class "+oldclazz.bytecodeName)
newpkg.classes get oldclazz.bytecodeName match {
View
33 reporter/src/main/scala/com/typesafe/tools/mima/lib/analyze/Analyzer.scala
@@ -60,6 +60,33 @@ private[analyze] trait Analyzer extends Function2[ClassInfo, ClassInfo, List[Pro
}
def analyzeNewClassMethods(oldclazz: ClassInfo, newclazz: ClassInfo): List[Problem]
+
+ protected def collectNewAbstractMethodsInNewInheritedTypes(oldclazz: ClassInfo, newclazz: ClassInfo): List[Problem] = {
+ def allInheritedTypes(clazz: ClassInfo) = clazz.superClasses ++ clazz.allInterfaces
+ val oldInheritedTypes = allInheritedTypes(oldclazz)
+ val newInheritedTypes = allInheritedTypes(newclazz)
+ val diff = newInheritedTypes.diff(oldInheritedTypes)
+ def noInheritedMatchingMethod(clazz: ClassInfo, deferredMethod: MemberInfo)(extraMethodMatchingCond: MemberInfo => Boolean): Boolean = {
+ val methods = clazz.lookupMethods(deferredMethod.bytecodeName)
+ val matchingMethods = methods.filter(_.matchesType(deferredMethod))
+
+ !matchingMethods.exists { method =>
+ method.owner != deferredMethod.owner &&
+ extraMethodMatchingCond(method)
+ }
+ }
+ (for {
+ tpe <- diff
+ // if `tpe` is a trait, then the trait's concrete methods should be counted as deferred methods
+ newDeferredMethod <- tpe.deferredMethodsInBytecode
+ // checks that the newDeferredMethod did not already exist in one of the oldclazz supertypes
+ if noInheritedMatchingMethod(oldclazz, newDeferredMethod)(_ => true) &&
+ // checks that no concrete implementation of the newDeferredMethod is provided by one of the newclazz supertypes
+ noInheritedMatchingMethod(newclazz, newDeferredMethod)(_.isConcrete)
+ } yield
+ // report a binary incompatibility as there is a new inherited abstract method, which can lead to a AbstractErrorMethod at runtime
+ InheritedNewAbstractMethodProblem(newclazz, newDeferredMethod))(collection.breakOut)
+ }
}
private[analyze] class ClassAnalyzer extends Analyzer {
@@ -78,7 +105,7 @@ private[analyze] class ClassAnalyzer extends Analyzer {
/** Analyze incompatibilities that may derive from methods in the `newclazz` */
override def analyzeNewClassMethods(oldclazz: ClassInfo, newclazz: ClassInfo): List[Problem] = {
- for (newAbstrMeth <- newclazz.deferredMethods) yield {
+ (for (newAbstrMeth <- newclazz.deferredMethods) yield {
oldclazz.lookupMethods(newAbstrMeth.bytecodeName).find(_.sig == newAbstrMeth.sig) match {
case None =>
Some(ReversedMissingMethodProblem(newAbstrMeth))
@@ -89,7 +116,7 @@ private[analyze] class ClassAnalyzer extends Analyzer {
else
None
}
- }
+ }) ::: collectNewAbstractMethodsInNewInheritedTypes(oldclazz, newclazz)
}
}
@@ -126,6 +153,8 @@ private[analyze] class TraitAnalyzer extends Analyzer {
}
}
+
+ res ++= collectNewAbstractMethodsInNewInheritedTypes(oldclazz, newclazz)
res.toList
}
}
View
6 reporter/src/main/scala/com/typesafe/tools/mima/lib/analyze/Checker.scala
@@ -8,13 +8,13 @@ private[analyze] trait Checker[T, S] extends Function2[T,S,Option[Problem]]{
def check(thisEl: T, thatEl: S): Option[Problem]
- protected def checkRules[T,S](rules: Seq[Rule[T, S]])(oldEl: T, newEl: S): Option[Problem] = {
+ protected def checkRules[T1,S1](rules: Seq[Rule[T1, S1]])(oldEl: T1, newEl: S1): Option[Problem] = {
if (rules.isEmpty) None
else {
val rule = rules.head
rule(oldEl, newEl) match {
- case None => checkRules(rules.tail)(oldEl, newEl)
- case res @ _ => res
+ case None => checkRules(rules.tail)(oldEl, newEl)
+ case res => res
}
}
}

0 comments on commit 9a2fe12

Please sign in to comment.