From 8262ed2fc618d27258eb975fd401b31f1064cc3e Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Tue, 25 Mar 2014 14:08:27 +0100 Subject: SI-8442 Ignore stub annotation symbols in `AnnotationInfo#matches` And update the java `ClassFileParser` to create distinguished `StubClassSymbol`s, rather that a regular `ClassSymbol`s, when encountering a deficient classpath. This brings it into line with `Unpickler`, which has done as much since a55788e275f. This stops the enclosed test case from crashing when determining if the absent symbol, `A_1`, is a subclass of `@deprecated`. This is ostensibly fixes a regression, although it only worked in `2.10.[0-3]` by a fluke: the class file parser's promiscious exception handling caught and recovered from the NPE introduced in SI-7439! % javac -d /tmp test/files/run/t8442/{A,B}_1.java && qbin/scalac -classpath /tmp -d /tmp test/files/run/t8442/C_2.scala && (rm /tmp/A_1.class; true) && scalac-hash v2.10.0 -classpath /tmp -d /tmp test/files/run/t8442/C_2.scala warning: Class A_1 not found - continuing with a stub. warning: Caught: java.lang.NullPointerException while parsing annotations in /tmp/B_1.class two warnings found --- .../nsc/symtab/classfile/ClassfileParser.scala | 10 +++++--- .../scala/reflect/internal/AnnotationInfos.scala | 2 +- test/files/run/t8442.check | 1 + test/files/run/t8442/A_1.java | 4 +++ test/files/run/t8442/B_1.java | 3 +++ test/files/run/t8442/C_2.scala | 5 ++++ test/files/run/t8442/Test.scala | 29 ++++++++++++++++++++++ 7 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 test/files/run/t8442.check create mode 100644 test/files/run/t8442/A_1.java create mode 100644 test/files/run/t8442/B_1.java create mode 100644 test/files/run/t8442/C_2.scala create mode 100644 test/files/run/t8442/Test.scala diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 2955986a7e..6991cfa37b 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -436,9 +436,13 @@ abstract class ClassfileParser { // SI-5593 Scaladoc's current strategy is to visit all packages in search of user code that can be documented // therefore, it will rummage through the classpath triggering errors whenever it encounters package objects // that are not in their correct place (see bug for details) - if (!settings.isScaladoc) - warning(s"Class $name not found - continuing with a stub.") - return NoSymbol.newClass(name.toTypeName) + + // TODO More consistency with use of stub symbols in `Unpickler` + // - better owner than `NoSymbol` + // - remove eager warning + val msg = s"Class $name not found - continuing with a stub." + if (!settings.isScaladoc) warning(msg) + return NoSymbol.newStubSymbol(name.toTypeName, msg) } val completer = new global.loaders.ClassfileLoader(file) var owner: Symbol = rootMirror.RootClass diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala index 032b45316e..80b6b16d0a 100644 --- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala +++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala @@ -292,7 +292,7 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable => */ def defaultTargets = symbol.annotations map (_.symbol) filter isMetaAnnotation // Test whether the typeSymbol of atp conforms to the given class. - def matches(clazz: Symbol) = symbol isNonBottomSubClass clazz + def matches(clazz: Symbol) = !symbol.isInstanceOf[StubSymbol] && (symbol isNonBottomSubClass clazz) // All subtrees of all args are considered. def hasArgWhich(p: Tree => Boolean) = args exists (_ exists p) diff --git a/test/files/run/t8442.check b/test/files/run/t8442.check new file mode 100644 index 0000000000..ce9e8b52ff --- /dev/null +++ b/test/files/run/t8442.check @@ -0,0 +1 @@ +pos: NoPosition Class A_1 not found - continuing with a stub. WARNING diff --git a/test/files/run/t8442/A_1.java b/test/files/run/t8442/A_1.java new file mode 100644 index 0000000000..227451eecd --- /dev/null +++ b/test/files/run/t8442/A_1.java @@ -0,0 +1,4 @@ +@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) +public @interface A_1 { + +} \ No newline at end of file diff --git a/test/files/run/t8442/B_1.java b/test/files/run/t8442/B_1.java new file mode 100644 index 0000000000..1680684495 --- /dev/null +++ b/test/files/run/t8442/B_1.java @@ -0,0 +1,3 @@ +public class B_1 { + @A_1 public String get() { return ""; } +} diff --git a/test/files/run/t8442/C_2.scala b/test/files/run/t8442/C_2.scala new file mode 100644 index 0000000000..d75d4bd910 --- /dev/null +++ b/test/files/run/t8442/C_2.scala @@ -0,0 +1,5 @@ +class C_2 { + def foo(b: B_1) { + b.get() + } +} diff --git a/test/files/run/t8442/Test.scala b/test/files/run/t8442/Test.scala new file mode 100644 index 0000000000..ff6da4e206 --- /dev/null +++ b/test/files/run/t8442/Test.scala @@ -0,0 +1,29 @@ +import scala.tools.partest._ +import java.io.File + +object Test extends StoreReporterDirectTest { + 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 = """ + class C_2 { + def foo(b: B_1) { + b.get() + } + } + """ + + def show(): Unit = { + val tClass = new File(testOutput.path, "A_1.class") + assert(tClass.exists) + assert(tClass.delete()) + + // Expecting stub symbol warning, but no stack trace! + compileCode(app) + println(filteredInfos.mkString("\n")) + } +} -- cgit v1.2.3