From 5096a5bb6508727a09ecd7cf7ef43bc1b5c530c6 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 29 May 2017 10:32:46 +0200 Subject: [PATCH 1/3] Fix #2556, make JUnit4 work in dotty compiled classes. https://github.com/scala/scala/commit/50b71b6c829faabfaa46197572fc4ddd03b7e9c1 --- .../src/dotty/tools/dotc/transform/MixinOps.scala | 11 ++++++++++- tests/run/junitForwarders/C_1.scala | 15 +++++++++++++++ tests/run/junitForwarders/Test.java | 10 ++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 tests/run/junitForwarders/C_1.scala create mode 100644 tests/run/junitForwarders/Test.java diff --git a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala index d91522c25f12..fb4696ac19a3 100644 --- a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala +++ b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala @@ -6,6 +6,7 @@ import Symbols._, Types._, Contexts._, SymDenotations._, DenotTransformers._, Fl import util.Positions._ import SymUtils._ import StdNames._, NameOps._ +import Decorators._ class MixinOps(cls: ClassSymbol, thisTransform: DenotTransformer)(implicit ctx: Context) { import ast.tpd._ @@ -13,6 +14,10 @@ class MixinOps(cls: ClassSymbol, thisTransform: DenotTransformer)(implicit ctx: val superCls: Symbol = cls.superClass val mixins: List[ClassSymbol] = cls.mixins + lazy val JUnit4Annotations: List[Symbol] = List("Test", "Ignore", "Before", "After", "BeforeClass", "AfterClass"). + map(n => ctx.getClassIfDefined("org.junit." + n)). + filter(_.exists) + def implementation(member: TermSymbol): TermSymbol = { val res = member.copy( owner = cls, @@ -59,10 +64,14 @@ class MixinOps(cls: ClassSymbol, thisTransform: DenotTransformer)(implicit ctx: def needsDisambiguation = competingMethods.exists(x=> !(x is Deferred)) // multiple implementations are available def hasNonInterfaceDefinition = competingMethods.exists(!_.owner.is(Trait)) // there is a definition originating from class meth.is(Method, butNot = PrivateOrAccessorOrDeferred) && - (meth.owner.is(Scala2x) || needsDisambiguation || hasNonInterfaceDefinition ) && + (meth.owner.is(Scala2x) || needsDisambiguation || hasNonInterfaceDefinition || needsJUnit4Fix(meth) ) && isCurrent(meth) } + private def needsJUnit4Fix(meth: Symbol): Boolean = { + meth.annotations.nonEmpty && JUnit4Annotations.exists(annot => annot.exists && meth.hasAnnotation(annot)) + } + /** Get `sym` of the method that needs a forwarder * Method needs a forwarder in those cases: * - there is a trait that defines a primitive version of implemented polymorphic method. diff --git a/tests/run/junitForwarders/C_1.scala b/tests/run/junitForwarders/C_1.scala new file mode 100644 index 000000000000..2af2026a6124 --- /dev/null +++ b/tests/run/junitForwarders/C_1.scala @@ -0,0 +1,15 @@ +trait T { + @org.junit.Test def foo = 0 +} + +class C extends T + +object Test extends App { + def check(c: Class[_], e: String) = { + val s = c.getDeclaredMethods.sortBy(_.getName).map(m => s"${m.getName} - ${m.getDeclaredAnnotations.mkString(", ")}").mkString(";") + assert(s == e, s"found: $s\nexpected: $e") + } + check(classOf[C], "foo - @org.junit.Test()") + // TODO scala-dev#213: should `foo$` really carry the @Test annotation? + check(classOf[T], "$init$ - ;foo - @org.junit.Test();foo$ - @org.junit.Test()") +} diff --git a/tests/run/junitForwarders/Test.java b/tests/run/junitForwarders/Test.java new file mode 100644 index 000000000000..57c4d5b544d8 --- /dev/null +++ b/tests/run/junitForwarders/Test.java @@ -0,0 +1,10 @@ +package org.junit; + +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.METHOD}) +public @interface Test { } From 25ce399328a6f85b319d69268edbfcb935632bd3 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 29 May 2017 11:09:47 +0200 Subject: [PATCH 2/3] MixinOps: drop unnecessary .exists. --- compiler/src/dotty/tools/dotc/transform/MixinOps.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala index fb4696ac19a3..ab94fe60e3d8 100644 --- a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala +++ b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala @@ -69,7 +69,7 @@ class MixinOps(cls: ClassSymbol, thisTransform: DenotTransformer)(implicit ctx: } private def needsJUnit4Fix(meth: Symbol): Boolean = { - meth.annotations.nonEmpty && JUnit4Annotations.exists(annot => annot.exists && meth.hasAnnotation(annot)) + meth.annotations.nonEmpty && JUnit4Annotations.exists(annot => meth.hasAnnotation(annot)) } /** Get `sym` of the method that needs a forwarder From 85b0c0f26f4b2bd918044068930c01b4a5c91da7 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 29 May 2017 11:10:05 +0200 Subject: [PATCH 3/3] Adapt junitForwarders test for Dotty. We don't generate foo$ method. --- tests/run/junitForwarders/C_1.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run/junitForwarders/C_1.scala b/tests/run/junitForwarders/C_1.scala index 2af2026a6124..6246e9436866 100644 --- a/tests/run/junitForwarders/C_1.scala +++ b/tests/run/junitForwarders/C_1.scala @@ -11,5 +11,5 @@ object Test extends App { } check(classOf[C], "foo - @org.junit.Test()") // TODO scala-dev#213: should `foo$` really carry the @Test annotation? - check(classOf[T], "$init$ - ;foo - @org.junit.Test();foo$ - @org.junit.Test()") + check(classOf[T], "$init$ - ;foo - @org.junit.Test()") }