summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2016-10-28 12:08:55 +0200
committerLukas Rytz <lukas.rytz@gmail.com>2016-10-28 12:08:55 +0200
commitae17256f1dcde4dd82008c6e355604d68d5a07b3 (patch)
tree6eb8e3ce569eaaa41a93fc34c9942f9810012822
parent47050ee4934f5bf78339c5d81583ab445a4318dd (diff)
downloadscala-ae17256f1dcde4dd82008c6e355604d68d5a07b3.tar.gz
scala-ae17256f1dcde4dd82008c6e355604d68d5a07b3.tar.bz2
scala-ae17256f1dcde4dd82008c6e355604d68d5a07b3.zip
For scala classfiles, only parse the scala signature annotation
Skipping other annotations not only saves some cycles / GC, but also prevents some spurious warnings / errors related to cyclic dependencies when parsing annotation arguments refering to members of the class.
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala69
-rw-r--r--test/files/neg/t7014.check5
-rw-r--r--test/files/neg/t7014.flags1
-rw-r--r--test/files/neg/t7014/ThreadSafety.java (renamed from test/files/pos/t7014/ThreadSafety.java)0
-rw-r--r--test/files/neg/t7014/ThreadSafetyLevel.java (renamed from test/files/pos/t7014/ThreadSafetyLevel.java)0
-rw-r--r--test/files/neg/t7014/t7014.scala (renamed from test/files/pos/t7014/t7014.scala)0
-rw-r--r--test/files/pos/t5165b.flags1
-rw-r--r--test/files/pos/t7551.flags1
-rw-r--r--test/files/pos/t7551/A.java9
-rw-r--r--test/files/pos/t7551/T.scala9
-rw-r--r--test/files/pos/t7551/Test.scala5
11 files changed, 76 insertions, 24 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index f1ccc29afc..e136fdf6d1 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -820,16 +820,19 @@ abstract class ClassfileParser {
// Java annotations on classes / methods / fields with RetentionPolicy.RUNTIME
case tpnme.RuntimeAnnotationATTR =>
if (isScalaAnnot || !isScala) {
- val scalaSigAnnot = parseAnnotations(attrLen)
- if (isScalaAnnot)
- scalaSigAnnot match {
- case Some(san: AnnotationInfo) =>
- val bytes =
- san.assocs.find({ _._1 == nme.bytes }).get._2.asInstanceOf[ScalaSigBytes].bytes
- unpickler.unpickle(bytes, 0, clazz, staticModule, in.file.name)
- case None =>
- throw new RuntimeException("Scala class file does not contain Scala annotation")
- }
+ // For Scala classfiles we are only interested in the scala signature annotations. Other
+ // annotations should be skipped (the pickle contains the symbol's annotations).
+ // Skipping them also prevents some spurious warnings / errors related to SI-7014,
+ // SI-7551, pos/5165b
+ val scalaSigAnnot = parseAnnotations(onlyScalaSig = isScalaAnnot)
+ if (isScalaAnnot) scalaSigAnnot match {
+ case Some(san: AnnotationInfo) =>
+ val bytes =
+ san.assocs.find({ _._1 == nme.bytes }).get._2.asInstanceOf[ScalaSigBytes].bytes
+ unpickler.unpickle(bytes, 0, clazz, staticModule, in.file.name)
+ case None =>
+ throw new RuntimeException("Scala class file does not contain Scala annotation")
+ }
debuglog("[class] << " + sym.fullName + sym.annotationsString)
}
else
@@ -863,6 +866,24 @@ abstract class ClassfileParser {
}
}
+ def skipAnnotArg(): Unit = {
+ u1 match {
+ case STRING_TAG | BOOL_TAG | BYTE_TAG | CHAR_TAG | SHORT_TAG |
+ INT_TAG | LONG_TAG | FLOAT_TAG | DOUBLE_TAG | CLASS_TAG =>
+ in.skip(2)
+
+ case ENUM_TAG =>
+ in.skip(4)
+
+ case ARRAY_TAG =>
+ val num = u2
+ for (i <- 0 until num) skipAnnotArg()
+
+ case ANNOTATION_TAG =>
+ parseAnnotation(u2, onlyScalaSig = true)
+ }
+ }
+
def parseAnnotArg: Option[ClassfileAnnotArg] = {
val tag = u1
val index = u2
@@ -896,7 +917,7 @@ abstract class ClassfileParser {
if (hasError) None
else Some(ArrayAnnotArg(arr.toArray))
case ANNOTATION_TAG =>
- parseAnnotation(index) map (NestedAnnotArg(_))
+ parseAnnotation(index, onlyScalaSig = false) map (NestedAnnotArg(_))
}
}
@@ -923,7 +944,7 @@ abstract class ClassfileParser {
/* Parse and return a single annotation. If it is malformed,
* return None.
*/
- def parseAnnotation(attrNameIndex: Int): Option[AnnotationInfo] = try {
+ def parseAnnotation(attrNameIndex: Int, onlyScalaSig: Boolean): Option[AnnotationInfo] = try {
val attrType = pool.getType(attrNameIndex)
val nargs = u2
val nvpairs = new ListBuffer[(Name, ClassfileAnnotArg)]
@@ -944,7 +965,8 @@ abstract class ClassfileParser {
case None => hasError = true
}
else
- parseAnnotArg match {
+ if (onlyScalaSig) skipAnnotArg()
+ else parseAnnotArg match {
case Some(c) => nvpairs += ((name, c))
case None => hasError = true
}
@@ -986,19 +1008,18 @@ abstract class ClassfileParser {
/* Parse a sequence of annotations and attaches them to the
* current symbol sym, except for the ScalaSignature annotation that it returns, if it is available. */
- def parseAnnotations(len: Int): Option[AnnotationInfo] = {
+ def parseAnnotations(onlyScalaSig: Boolean): Option[AnnotationInfo] = {
val nAttr = u2
var scalaSigAnnot: Option[AnnotationInfo] = None
- for (n <- 0 until nAttr)
- parseAnnotation(u2) match {
- case Some(scalaSig) if (scalaSig.atp == ScalaSignatureAnnotation.tpe) =>
- scalaSigAnnot = Some(scalaSig)
- case Some(scalaSig) if (scalaSig.atp == ScalaLongSignatureAnnotation.tpe) =>
- scalaSigAnnot = Some(scalaSig)
- case Some(annot) =>
- sym.addAnnotation(annot)
- case None =>
- }
+ for (n <- 0 until nAttr) parseAnnotation(u2, onlyScalaSig) match {
+ case Some(scalaSig) if scalaSig.atp == ScalaSignatureAnnotation.tpe =>
+ scalaSigAnnot = Some(scalaSig)
+ case Some(scalaSig) if scalaSig.atp == ScalaLongSignatureAnnotation.tpe =>
+ scalaSigAnnot = Some(scalaSig)
+ case Some(annot) =>
+ sym.addAnnotation(annot)
+ case None =>
+ }
scalaSigAnnot
}
diff --git a/test/files/neg/t7014.check b/test/files/neg/t7014.check
new file mode 100644
index 0000000000..07ad51e9d3
--- /dev/null
+++ b/test/files/neg/t7014.check
@@ -0,0 +1,5 @@
+warning: While parsing annotations in t7014-neg.obj/t7014/ThreadSafetyLevel.class, could not find COMPLETELY_THREADSAFE in enum object ThreadSafetyLevel.
+This is likely due to an implementation restriction: an annotation argument cannot refer to a member of the annotated class (SI-7014).
+error: No warnings can be incurred under -Xfatal-warnings.
+one warning found
+one error found
diff --git a/test/files/neg/t7014.flags b/test/files/neg/t7014.flags
new file mode 100644
index 0000000000..85d8eb2ba2
--- /dev/null
+++ b/test/files/neg/t7014.flags
@@ -0,0 +1 @@
+-Xfatal-warnings
diff --git a/test/files/pos/t7014/ThreadSafety.java b/test/files/neg/t7014/ThreadSafety.java
index ed508804e3..ed508804e3 100644
--- a/test/files/pos/t7014/ThreadSafety.java
+++ b/test/files/neg/t7014/ThreadSafety.java
diff --git a/test/files/pos/t7014/ThreadSafetyLevel.java b/test/files/neg/t7014/ThreadSafetyLevel.java
index 4df1dc787a..4df1dc787a 100644
--- a/test/files/pos/t7014/ThreadSafetyLevel.java
+++ b/test/files/neg/t7014/ThreadSafetyLevel.java
diff --git a/test/files/pos/t7014/t7014.scala b/test/files/neg/t7014/t7014.scala
index 7c73f700be..7c73f700be 100644
--- a/test/files/pos/t7014/t7014.scala
+++ b/test/files/neg/t7014/t7014.scala
diff --git a/test/files/pos/t5165b.flags b/test/files/pos/t5165b.flags
new file mode 100644
index 0000000000..e8fb65d50c
--- /dev/null
+++ b/test/files/pos/t5165b.flags
@@ -0,0 +1 @@
+-Xfatal-warnings \ No newline at end of file
diff --git a/test/files/pos/t7551.flags b/test/files/pos/t7551.flags
new file mode 100644
index 0000000000..e8fb65d50c
--- /dev/null
+++ b/test/files/pos/t7551.flags
@@ -0,0 +1 @@
+-Xfatal-warnings \ No newline at end of file
diff --git a/test/files/pos/t7551/A.java b/test/files/pos/t7551/A.java
new file mode 100644
index 0000000000..72aeb40fa0
--- /dev/null
+++ b/test/files/pos/t7551/A.java
@@ -0,0 +1,9 @@
+package p;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface A {
+ Class<?> subInterface();
+}
diff --git a/test/files/pos/t7551/T.scala b/test/files/pos/t7551/T.scala
new file mode 100644
index 0000000000..017926e0e2
--- /dev/null
+++ b/test/files/pos/t7551/T.scala
@@ -0,0 +1,9 @@
+package p
+
+@A(subInterface = classOf[T.S])
+trait T {
+}
+
+object T {
+ private[p] trait S extends T { }
+}
diff --git a/test/files/pos/t7551/Test.scala b/test/files/pos/t7551/Test.scala
new file mode 100644
index 0000000000..c1f529c4b1
--- /dev/null
+++ b/test/files/pos/t7551/Test.scala
@@ -0,0 +1,5 @@
+package p
+
+object Foo {
+ def bar(t: T) { }
+}