Skip to content

Commit 2c50123

Browse files
authored
Merge pull request scala#5822 from lrytz/t9937
SI-9937 find nested java classes if InnnerClass entry is missing
2 parents 34da49b + 04d4f4c commit 2c50123

File tree

4 files changed

+65
-4
lines changed

4 files changed

+65
-4
lines changed

src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -380,11 +380,41 @@ abstract class ClassfileParser {
380380
}
381381

382382
private def lookupClass(name: Name) = try {
383-
if (name containsChar '.')
384-
rootMirror getClassByName name
385-
else
383+
def lookupTopLevel = {
384+
if (name containsChar '.')
385+
rootMirror getClassByName name
386+
else
386387
// FIXME - we shouldn't be doing ad hoc lookups in the empty package, getClassByName should return the class
387-
definitions.getMember(rootMirror.EmptyPackageClass, name.toTypeName)
388+
definitions.getMember(rootMirror.EmptyPackageClass, name.toTypeName)
389+
}
390+
391+
// For inner classes we usually don't get here: `classNameToSymbol` already returns the symbol
392+
// of the inner class based on the InnerClass table. However, if the classfile is missing the
393+
// InnerClass entry for `name`, it might still be that there exists an inner symbol (because
394+
// some other classfile _does_ have an InnerClass entry for `name`). In this case, we want to
395+
// return the actual inner symbol (C.D, with owner C), not the top-level symbol C$D. This is
396+
// what the logic below is for (see PR #5822 / scala/bug#9937).
397+
val split = if (isScalaRaw) -1 else name.lastIndexOf('$')
398+
if (split > 0 && split < name.length) {
399+
val outerName = name.subName(0, split)
400+
val innerName = name.subName(split + 1, name.length).toTypeName
401+
val outerSym = classNameToSymbol(outerName)
402+
403+
// If the outer class C cannot be found, look for a top-level class C$D
404+
if (outerSym.isInstanceOf[StubSymbol]) lookupTopLevel
405+
else {
406+
// We have a java-defined class name C$D and look for a member D of C. But we don't know if
407+
// D is declared static or not, so we have to search both in class C and its companion.
408+
val r = if (outerSym == clazz)
409+
staticScope.lookup(innerName) orElse
410+
instanceScope.lookup(innerName)
411+
else
412+
lookupMemberAtTyperPhaseIfPossible(outerSym, innerName) orElse
413+
lookupMemberAtTyperPhaseIfPossible(outerSym.companionModule, innerName)
414+
r orElse lookupTopLevel
415+
}
416+
} else
417+
lookupTopLevel
388418
} catch {
389419
// The handler
390420
// - prevents crashes with deficient InnerClassAttributes (scala/bug#2464, 0ce0ad5)

test/files/run/t9937/Test_1.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class C$D { public int i() { return 1; } }
2+
class C$E { public int i() { return 1; } }
3+
class C$F$G { public int i() { return 1; } }
4+
5+
// Test1 has a reference to C$D, which is a top-level class in this case,
6+
// so there's no INNERCLASS attribute in Test1
7+
class Test_1 {
8+
static C$D mD(C$D cd) { return cd; }
9+
static C$E mE(C$E ce) { return ce; }
10+
static C$F$G mG(C$F$G cg ) { return cg; }
11+
}

test/files/run/t9937/Test_2.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
class C {
2+
class D { public int i() { return 2; } }
3+
static class E { public int i() { return 2; } }
4+
static class F { static class G { public int i() { return 2; } } }
5+
}
6+
7+
// Test2 has an INNERCLASS attribute for C$D
8+
class Test_2 {
9+
public static int acceptD(C.D cd) { return cd.i(); }
10+
public static int acceptE(C.E ce) { return ce.i(); }
11+
public static int acceptG(C.F.G cg ) { return cg.i(); }
12+
}

test/files/run/t9937/Test_3.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
object Test {
2+
def main(args: Array[String]): Unit = {
3+
val c = new C
4+
assert(Test_2.acceptD(Test_1.mD(new c.D)) == 2)
5+
assert(Test_2.acceptE(Test_1.mE(new C.E)) == 2)
6+
assert(Test_2.acceptG(Test_1.mG(new C.F.G)) == 2)
7+
}
8+
}

0 commit comments

Comments
 (0)