Skip to content

Commit 014b33f

Browse files
authored
Merge pull request #143 from szeiger/issue/127-removing-inner-object
Detect changes to inner modules
2 parents e083f6d + 615b35a commit 014b33f

File tree

9 files changed

+48
-13
lines changed

9 files changed

+48
-13
lines changed

core/src/main/scala/com/typesafe/tools/mima/core/ClassInfo.scala

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ abstract class ClassInfo(val owner: PackageInfo) extends HasDeclarationName with
5656
else owner.fullName + "." + bytecodeName
5757
}
5858

59+
var _innerClasses: Seq[String] = Seq.empty
60+
def innerClasses = { ensureLoaded(); _innerClasses }
61+
62+
var _isTopLevel = true
63+
def isTopLevel = { ensureLoaded(); _isTopLevel }
64+
5965
final override def equals(other: Any): Boolean = other match {
6066
case that: ClassInfo => (that canEqual this) && this.fullName == that.fullName
6167
case _ => false
@@ -65,10 +71,10 @@ abstract class ClassInfo(val owner: PackageInfo) extends HasDeclarationName with
6571

6672
override def canEqual(other: Any) = other.isInstanceOf[ClassInfo]
6773

68-
def formattedFullName = formatClassName(if (isObject) fullName.init else fullName)
74+
def formattedFullName = formatClassName(if (isModule) fullName.init else fullName)
6975

7076
def declarationPrefix = {
71-
if (isObject) "object"
77+
if (isModule) "object"
7278
else if (isTrait) "trait"
7379
else if (loaded && isInterface) "interface" // java interfaces and traits with no implementation methods
7480
else "class"
@@ -290,7 +296,7 @@ abstract class ClassInfo(val owner: PackageInfo) extends HasDeclarationName with
290296
ClassfileParser.isInterface(flags)
291297
}
292298

293-
def isObject: Boolean = bytecodeName.endsWith("$")
299+
def isModule: Boolean = bytecodeName.endsWith("$")
294300

295301
/** Is this class public? */
296302
/*

core/src/main/scala/com/typesafe/tools/mima/core/ClassfileParser.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,17 @@ abstract class ClassfileParser(definitions: Definitions) {
267267
val attrNameIndex = in.nextChar
268268
c.sourceFileName = pool.getName(attrNameIndex)
269269
}
270+
} else if (attrName == "InnerClasses") {
271+
val entries = in.nextChar.toInt
272+
c._innerClasses = (0 until entries).map { _ =>
273+
val innerIndex, outerIndex, innerNameIndex = in.nextChar.toInt
274+
in.skip(2)
275+
if (innerIndex != 0 && outerIndex != 0 && innerNameIndex != 0) {
276+
val n = pool.getClassName(innerIndex)
277+
if (n == c.bytecodeName) c._isTopLevel = false // an inner class lists itself in InnerClasses
278+
if (pool.getClassName(outerIndex) == c.bytecodeName) n else ""
279+
} else ""
280+
}.filterNot(_.isEmpty)
270281
} else if (attrName == "Scala" || attrName == "ScalaSig") {
271282
this.parsedClass.isScala = true
272283
}

core/src/main/scala/com/typesafe/tools/mima/core/PackageInfo.scala

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.typesafe.tools.mima.core
22

3+
import scala.annotation.tailrec
34
import scala.tools.nsc.io.AbstractFile
45
import scala.tools.nsc.util.ClassPath
56
import collection.mutable
@@ -65,25 +66,23 @@ abstract class PackageInfo(val owner: PackageInfo) {
6566

6667
lazy val accessibleClasses: Set[ClassInfo] = {
6768
/** Fixed point iteration for finding all accessible classes. */
68-
def accessibleClassesUnder(prefix: Set[ClassInfo]): Set[ClassInfo] = {
69-
val vclasses = (classes.valuesIterator filter (isAccessible(_, prefix))).toSet
70-
if (vclasses.isEmpty) vclasses
71-
else vclasses union accessibleClassesUnder(vclasses)
69+
@tailrec
70+
def accessibleClassesUnder(prefix: Set[ClassInfo], found: Set[ClassInfo]): Set[ClassInfo] = {
71+
val vclasses = (classes.valuesIterator.filter(isAccessible(_, prefix))).toSet
72+
if (vclasses.isEmpty) found
73+
else accessibleClassesUnder(vclasses, vclasses union found)
7274
}
7375

7476
def isAccessible(clazz: ClassInfo, prefix: Set[ClassInfo]) = {
7577
def isReachable = {
7678
if (clazz.isSynthetic) false
77-
else {
78-
val idx = clazz.decodedName.lastIndexOf("$")
79-
if (idx < 0) prefix.isEmpty // class name contains no $
80-
else prefix exists (_.decodedName == clazz.decodedName.substring(0, idx)) // prefix before dollar is an accessible class detected previously
81-
}
79+
else if (prefix.isEmpty) clazz.isTopLevel && !clazz.bytecodeName.contains("$$")
80+
else prefix.exists(_.innerClasses contains clazz.bytecodeName)
8281
}
8382
clazz.isPublic && isReachable
8483
}
8584

86-
accessibleClassesUnder(Set.empty)
85+
accessibleClassesUnder(Set.empty, Set.empty)
8786
}
8887

8988
/** All implementation classes of traits (classes that end in "$" followed by "class"). */
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
object A#B does not have a correspondent in new version
2+
method B()A#B# in class A does not have a correspondent in new version
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class A {
2+
object B {
3+
def foo: Int = 2
4+
}
5+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
class A {
2+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
object A#B does not have a correspondent in new version
2+
object A#B#C does not have a correspondent in new version
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
object A {
2+
object B {
3+
def foo: Int = 2
4+
object C
5+
}
6+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
object A {
2+
}

0 commit comments

Comments
 (0)