summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-06-08 12:13:45 -0700
committerPaul Phillips <paulp@improving.org>2013-06-08 12:13:45 -0700
commit20f8eacca4f4b0bbc2c5f9045a87f8b003ba8876 (patch)
treefb4ee61f50fe1bc8e55257c4301b186491cb8821
parent04837e710552cc53b0b06b2bc47ee7d2856ae230 (diff)
parent2a19cd56258884e25f26565d7b865cc2ec931b23 (diff)
downloadscala-20f8eacca4f4b0bbc2c5f9045a87f8b003ba8876.tar.gz
scala-20f8eacca4f4b0bbc2c5f9045a87f8b003ba8876.tar.bz2
scala-20f8eacca4f4b0bbc2c5f9045a87f8b003ba8876.zip
Merge pull request #2639 from retronym/ticket/2464
SI-2464 Resiliance against missing InnerClass attributes
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala12
-rw-r--r--src/partest/scala/tools/partest/BytecodeTest.scala35
-rw-r--r--test/files/run/t2464/Annotated.java5
-rw-r--r--test/files/run/t2464/Connect.java20
-rw-r--r--test/files/run/t2464/Test.scala35
5 files changed, 99 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 fb927d15d3..1e84c73633 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -588,10 +588,14 @@ abstract class ClassfileParser {
// sealed java enums
if (jflags.isEnum) {
val enumClass = sym.owner.linkedClassOfClass
- if (!enumClass.isSealed)
- enumClass setFlag (SEALED | ABSTRACT)
-
- enumClass addChild sym
+ enumClass match {
+ case NoSymbol =>
+ devWarning(s"no linked class for java enum $sym in ${sym.owner}. A referencing class file might be missing an InnerClasses entry.")
+ case linked =>
+ if (!linked.isSealed)
+ linked setFlag (SEALED | ABSTRACT)
+ linked addChild sym
+ }
}
}
}
diff --git a/src/partest/scala/tools/partest/BytecodeTest.scala b/src/partest/scala/tools/partest/BytecodeTest.scala
index 2699083069..172fa29189 100644
--- a/src/partest/scala/tools/partest/BytecodeTest.scala
+++ b/src/partest/scala/tools/partest/BytecodeTest.scala
@@ -2,10 +2,9 @@ package scala.tools.partest
import scala.tools.nsc.util.JavaClassPath
import scala.collection.JavaConverters._
-import scala.tools.asm
-import asm.{ ClassReader }
-import asm.tree.{ClassNode, MethodNode, InsnList}
-import java.io.InputStream
+import scala.tools.asm.{ClassWriter, ClassReader}
+import scala.tools.asm.tree.{ClassNode, MethodNode, InsnList}
+import java.io.{FileOutputStream, FileInputStream, File => JFile, InputStream}
import AsmNode._
/**
@@ -127,3 +126,31 @@ abstract class BytecodeTest extends ASMConverters {
new JavaClassPath(containers, DefaultJavaContext)
}
}
+
+object BytecodeTest {
+ /** Parse `file` as a class file, transforms the ASM representation with `f`,
+ * and overwrites the orginal file.
+ */
+ def modifyClassFile(file: JFile)(f: ClassNode => ClassNode) {
+ val rfile = new reflect.io.File(file)
+ def readClass: ClassNode = {
+ val cr = new ClassReader(rfile.toByteArray())
+ val cn = new ClassNode()
+ cr.accept(cn, 0)
+ cn
+ }
+
+ def writeClass(cn: ClassNode) {
+ val writer = new ClassWriter(0)
+ cn.accept(writer)
+ val os = rfile.bufferedOutput()
+ try {
+ os.write(writer.toByteArray)
+ } finally {
+ os.close()
+ }
+ }
+
+ writeClass(f(readClass))
+ }
+}
diff --git a/test/files/run/t2464/Annotated.java b/test/files/run/t2464/Annotated.java
new file mode 100644
index 0000000000..d022f9852c
--- /dev/null
+++ b/test/files/run/t2464/Annotated.java
@@ -0,0 +1,5 @@
+package test;
+
+@Connect(loadStyle = Connect.LoadStyle.EAGER)
+public class Annotated {
+}
diff --git a/test/files/run/t2464/Connect.java b/test/files/run/t2464/Connect.java
new file mode 100644
index 0000000000..59349f94c8
--- /dev/null
+++ b/test/files/run/t2464/Connect.java
@@ -0,0 +1,20 @@
+package test;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface Connect {
+
+ LoadStyle loadStyle() default LoadStyle.EAGER;
+
+ public enum LoadStyle {
+ EAGER,
+ DEFERRED,
+ LAZY
+ }
+}
diff --git a/test/files/run/t2464/Test.scala b/test/files/run/t2464/Test.scala
new file mode 100644
index 0000000000..90e1a03c17
--- /dev/null
+++ b/test/files/run/t2464/Test.scala
@@ -0,0 +1,35 @@
+import scala.reflect.io.Streamable
+import scala.tools.asm.{ClassWriter, ClassReader}
+import scala.tools.asm.tree.ClassNode
+import scala.tools.partest._
+import scala.tools.partest.BytecodeTest.modifyClassFile
+import java.io.{FileOutputStream, FileInputStream, File}
+
+object Test extends DirectTest {
+ def code = ???
+
+ def compileCode(code: String) = {
+ val classpath = List(sys.props("partest.lib"), testOutput.path) mkString sys.props("path.separator")
+ compileString(newCompiler("-cp", classpath, "-d", testOutput.path))(code)
+ }
+
+ def app = """
+ object O {
+ new test.Annotated
+ }
+ """
+
+ def show(): Unit = {
+ compileCode(app)
+ modifyClassFile(new File(testOutput.toFile, "test/Annotated.class")) {
+ (cn: ClassNode) =>
+ // As investigated https://issues.scala-lang.org/browse/SI-2464?focusedCommentId=64521&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-64521
+ // classfiles in the wild sometimes lack the required InnerClass attribute for nested enums that
+ // are referenced in an annotation. I don't know what compiler or bytecode processor leaves things
+ // that way, but this test makes sure we don't crash.
+ cn.innerClasses.clear()
+ cn
+ }
+ compileCode(app)
+ }
+}