diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2015-03-02 15:48:25 +1000 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2015-03-25 11:59:54 +1000 |
commit | bbd693ae44bab4be2be7930641f8ca2bf27c962c (patch) | |
tree | 5a9acd0c2d3e201f0c616e2ee3f359b22218924e /src/compiler/scala/tools/nsc/symtab/classfile | |
parent | 52d4a5ac00af05648d3afae79b7428ef19ae5c21 (diff) | |
download | scala-bbd693ae44bab4be2be7930641f8ca2bf27c962c.tar.gz scala-bbd693ae44bab4be2be7930641f8ca2bf27c962c.tar.bz2 scala-bbd693ae44bab4be2be7930641f8ca2bf27c962c.zip |
SI-7741 Tread more lightly during classfile parsing
1. Avoid forcing info of non-Scala interface members
This avoids parsing the ostensibly malformed class definitions that
correspond to a Groovy lambda defined in an interface.
2. Be more tolerant of absent inner classfiles
Taking a leaf out of javac's book (see transcript below),
we can use stub symbols for InnerClass entries that don't
have corresponding class files on the compilation classpath.
This will limit failures to code that directly refers to the
inner class, rather than any code that simply refers to the
enclosing class.
It seems that groovyc has a habit of emitting incongrous
bytecode in this regard. But this change seems generally
useful.
```
% cat sandbox/{Test,Client}.java
public class Test {
public class Inner {}
}
public class Client {
public Test.Inner x() { return null; }
}
% javac -d . sandbox/Test.java && javac -classpath . sandbox/Client.java
% javac -d . sandbox/Test.java && rm 'Test$Inner.class' && javac -classpath . sandbox/Client.java
sandbox/Client.java:2: error: cannot access Inner
public Test.Inner x() { return null; }
^
class file for Test$Inner not found
1 error
% cat sandbox/{Test,Client}.java
public class Test {
public class Inner {}
}
public class Client {
public Test.NeverExisted x() { return null; }
}
% javac -classpath . sandbox/Client.java
sandbox/Client.java:2: error: cannot find symbol
public Test.NeverExisted x() { return null; }
^
symbol: class NeverExisted
location: class Test
1 error
% cat sandbox/{Test,Client}.java
public class Test {
public class Inner {}
}
public class Client {
public Test x() { return null; }
}
topic/groovy-interop ~/code/scala2 javac -d . sandbox/Test.java && rm 'Test$Inner.class' && javac -classpath . sandbox/Client.java # allowed
```
Diffstat (limited to 'src/compiler/scala/tools/nsc/symtab/classfile')
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala | 22 |
1 files changed, 14 insertions, 8 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 4d08be3c24..602d18a651 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -15,6 +15,7 @@ import scala.collection.mutable.{ ListBuffer, ArrayBuffer } import scala.annotation.switch import scala.reflect.internal.{ JavaAccFlags } import scala.reflect.internal.pickling.{PickleBuffer, ByteCodecs} +import scala.reflect.io.NoAbstractFile import scala.tools.nsc.io.AbstractFile import scala.tools.nsc.util.ClassFileLookup @@ -1022,11 +1023,18 @@ abstract class ClassfileParser { val sflags = jflags.toScalaFlags val owner = ownerForFlags(jflags) val scope = getScope(jflags) - val innerClass = owner.newClass(name.toTypeName, NoPosition, sflags) setInfo completer - val innerModule = owner.newModule(name.toTermName, NoPosition, sflags) setInfo completer + def newStub(name: Name) = + owner.newStubSymbol(name, s"Class file for ${entry.externalName} not found").setFlag(JAVA) - innerModule.moduleClass setInfo loaders.moduleClassLoader - List(innerClass, innerModule.moduleClass) foreach (_.associatedFile = file) + val (innerClass, innerModule) = if (file == NoAbstractFile) { + (newStub(name.toTypeName), newStub(name.toTermName)) + } else { + val cls = owner.newClass(name.toTypeName, NoPosition, sflags) setInfo completer + val mod = owner.newModule(name.toTermName, NoPosition, sflags) setInfo completer + mod.moduleClass setInfo loaders.moduleClassLoader + List(cls, mod.moduleClass) foreach (_.associatedFile = file) + (cls, mod) + } scope enter innerClass scope enter innerModule @@ -1046,10 +1054,8 @@ abstract class ClassfileParser { for (entry <- innerClasses.entries) { // create a new class member for immediate inner classes if (entry.outerName == currentClass) { - val file = classFileLookup.findClassFile(entry.externalName.toString) getOrElse { - throw new AssertionError(s"Class file for ${entry.externalName} not found") - } - enterClassAndModule(entry, file) + val file = classFileLookup.findClassFile(entry.externalName.toString) + enterClassAndModule(entry, file.getOrElse(NoAbstractFile)) } } } |