Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SI-9937 find nested java classes if InnerClass entry is missing #5822

Merged
merged 1 commit into from
Jun 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -380,11 +380,41 @@ abstract class ClassfileParser {
}

private def lookupClass(name: Name) = try {
if (name containsChar '.')
rootMirror getClassByName name
else
def lookupTopLevel = {
if (name containsChar '.')
rootMirror getClassByName name
else
// FIXME - we shouldn't be doing ad hoc lookups in the empty package, getClassByName should return the class
definitions.getMember(rootMirror.EmptyPackageClass, name.toTypeName)
definitions.getMember(rootMirror.EmptyPackageClass, name.toTypeName)
}

// For inner classes we usually don't get here: `classNameToSymbol` already returns the symbol
// of the inner class based on the InnerClass table. However, if the classfile is missing the
// InnerClass entry for `name`, it might still be that there exists an inner symbol (because
// some other classfile _does_ have an InnerClass entry for `name`). In this case, we want to
// return the actual inner symbol (C.D, with owner C), not the top-level symbol C$D. This is
// what the logic below is for (see PR #5822 / scala/bug#9937).
val split = if (isScalaRaw) -1 else name.lastIndexOf('$')
if (split > 0 && split < name.length) {
val outerName = name.subName(0, split)
val innerName = name.subName(split + 1, name.length).toTypeName
val outerSym = classNameToSymbol(outerName)

// If the outer class C cannot be found, look for a top-level class C$D
if (outerSym.isInstanceOf[StubSymbol]) lookupTopLevel
else {
// We have a java-defined class name C$D and look for a member D of C. But we don't know if
// D is declared static or not, so we have to search both in class C and its companion.
val r = if (outerSym == clazz)
staticScope.lookup(innerName) orElse
instanceScope.lookup(innerName)
else
lookupMemberAtTyperPhaseIfPossible(outerSym, innerName) orElse
lookupMemberAtTyperPhaseIfPossible(outerSym.companionModule, innerName)
r orElse lookupTopLevel
}
} else
lookupTopLevel
} catch {
// The handler
// - prevents crashes with deficient InnerClassAttributes (scala/bug#2464, 0ce0ad5)
Expand Down
11 changes: 11 additions & 0 deletions test/files/run/t9937/Test_1.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class C$D { public int i() { return 1; } }
class C$E { public int i() { return 1; } }
class C$F$G { public int i() { return 1; } }

// Test1 has a reference to C$D, which is a top-level class in this case,
// so there's no INNERCLASS attribute in Test1
class Test_1 {
static C$D mD(C$D cd) { return cd; }
static C$E mE(C$E ce) { return ce; }
static C$F$G mG(C$F$G cg ) { return cg; }
}
12 changes: 12 additions & 0 deletions test/files/run/t9937/Test_2.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class C {
class D { public int i() { return 2; } }
static class E { public int i() { return 2; } }
static class F { static class G { public int i() { return 2; } } }
}

// Test2 has an INNERCLASS attribute for C$D
class Test_2 {
public static int acceptD(C.D cd) { return cd.i(); }
public static int acceptE(C.E ce) { return ce.i(); }
public static int acceptG(C.F.G cg ) { return cg.i(); }
}
8 changes: 8 additions & 0 deletions test/files/run/t9937/Test_3.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
object Test {
def main(args: Array[String]): Unit = {
val c = new C
assert(Test_2.acceptD(Test_1.mD(new c.D)) == 2)
assert(Test_2.acceptE(Test_1.mE(new C.E)) == 2)
assert(Test_2.acceptG(Test_1.mG(new C.F.G)) == 2)
}
}